ホーム 記事一覧 ブック DH週間トピックス 検索 このサイトについて
English

TEI XMLのスタンドオフ注釈をインライン化する際の落とし穴とDOM操作による解決

デジタル延喜式は、延長5年(927年)に完成した律令の施行細則集『延喜式』を TEI (Text Encoding Initiative) XML で符号化し、Web上で閲覧・検索できるようにするプロジェクトです。国立歴史民俗博物館を中心に、校訂文・現代語訳・英訳を TEI でマークアップし、Nuxt.js(Vue.js)ベースのビューアで公開しています。 この開発の中で、TEI XML のスタンドオフ(standoff)注釈をインライン注釈に変換する処理において、XML の文書構造が崩壊するバグに遭遇しました。本記事では、その原因と DOM 操作ベースの解決策を記録します。 スタンドオフ注釈とは TEI XML では、テキスト中の校異(variant readings)を記録する方法として、スタンドオフ方式がよく使われます。デジタル延喜式では、複数の写本間のテキストの異同を <app> 要素で記録しており、テキスト中に <anchor> 要素で範囲を示し、対応する <app> 要素を別の場所に置く構造になっています。 <p> 前テキスト <anchor xml:id="app001"/> 校異対象のテキスト <anchor xml:id="app001e"/> 後テキスト </p> <!-- 別の場所に校異情報 --> <app from="#app001" to="#app001e"> <lem>校異対象のテキスト</lem> <rdg wit="#写本A">異なるテキスト</rdg> </app> この方式は、XML のネスト制約を回避できる利点があります。校異の範囲が要素境界をまたぐ場合(overlapping hierarchy)でも、anchor はどこにでも置けるためです。 インライン化の理由 XML ツリーと UI コンポーネントツリーの対応 デジタル延喜式のビューアは Vue.js で構築しています。Vue.js や React のようなコンポーネントベースのフレームワークでは、UI はツリー構造で記述されます。TEI XML もツリー構造なので、XML の各要素を UI コンポーネントに 1:1 でマッピングする再帰レンダリングが自然なアプローチになります。 <!-- TEI.vue: XML要素を再帰的にコンポーネントにマッピング --> <template> <component v-for="child in element.children" :is="getComponent(child.tagName)" :element="child" /> </template> この設計では、<app> 要素がテキスト中にインラインで存在すれば、ツリーの走査だけでレンダリングできます。 ...

Claude Codeで6件のGitHub Issueを並行対応:worktreeとagentの活用

Claude Codeで6件のGitHub Issueを並行対応:worktreeとagentの活用

はじめに TEI/XMLで構造化された歴史史料をWeb上で閲覧できるビューアを、Nuxt 2 + Vue 2 + Vuetifyで開発しています。このプロジェクトに報告された6件のGitHub Issueに対して、Claude Codeのworktree機能とagentを活用して並行対応した記録を紹介します。 対応したIssue一覧 グループ Issue数 内容 優先度 A 3件 テキストビューワの入れ子要素の表示不具合 高 B 1件 凡例ページのインデント未反映 中 C 1件 分析ページのリンク切れ 高 D 1件 キーワード検索のクラッシュ 高 アプローチ:worktree × 並行agent Claude Codeには、git worktreeを使って独立した作業環境で複数のagentを並行実行する機能があります。今回は上記4グループに対して、4つのagentを同時に起動しました。 各agentがworktreeで独立して作業するため、互いに干渉せず並行して修正を進められます。 Agent 1: fix/nested-tags → グループA(3件、同一の根本原因) Agent 2: fix/legend-indent → グループB Agent 3: fix/analytics-links → グループC Agent 4: fix/keyword-search → グループD 各Issueの修正内容 グループD:検索プラグインのクラッシュ 原因: 検索プラグイン内で、環境変数から読み込む設定値がundefinedのため、検索実行時にTypeErrorでクラッシュしていました。 修正: 1行のnullガード追加で解決しました。最もシンプルな修正でしたが、agentが原因を正確に特定してくれました。 グループA:入れ子要素の表示不具合 3件のIssueは一見別々の問題に見えましたが、すべて共通の根本原因を持っていました。 原因: TEI XMLの前処理スクリプトが、入れ子構造の要素を正しく変換していませんでした。具体的には、テキスト範囲を示すアンカーペアを要素に変換する処理で、入れ子になった内側の要素がフィルタリングで除外されていたため、テキストやクリック可能な注釈が失われていました。 修正: 前処理スクリプトに3つの変更を加えました。 ...

TEI Publisher:TEI XMLデジタルエディション出版プラットフォーム

TEI Publisher:TEI XMLデジタルエディション出版プラットフォーム

はじめに TEI(Text Encoding Initiative)は、人文学のテキストをデジタル化する際の国際標準として広く採用されている XML マークアップ言語です。古典籍、書簡、碑文、辞書など、さまざまなテキスト資料を構造化された形式で記述できます。 しかし、TEI XML で符号化されたテキストを、読みやすい形で Web 上に公開するには、相応の技術的知識が必要です。本記事では、TEI XML のデジタルエディションを簡単に出版できるプラットフォーム TEI Publisher を紹介します。 TEI Publisher とは TEI Publisher は、eXist-db XML データベース上で動作するデジタルエディション出版プラットフォームです。TEI XML で符号化されたテキストを、カスタマイズ可能な美しい Web ページとして公開できます。 e-editiones コミュニティによって開発・メンテナンスされており、オープンソースとして公開されています。学術的なテキスト出版のためのワンストップソリューションを目指しています。 主な機能 カスタマイズ可能な表示 ODD(One Document Does it all)仕様に基づく処理モデルにより、TEI XML の各要素をどのように表示するかを柔軟に定義できます。XSLT を直接書く必要はなく、GUI ベースのエディタで表示ルールを設定できます。 ファクシミリ表示 原本のデジタル画像(ファクシミリ)とテキストの翻刻を並べて表示できます。IIIF Image API にも対応しており、高解像度画像のズーム表示が可能です。テキストの特定箇所と画像の対応する領域をリンクさせることもできます。 全文検索 eXist-db の全文検索エンジンにより、テキスト全体を高速に検索できます。Lucene ベースのインデックスにより、大量のテキストでも即座に結果を返します。ファセット検索やハイライト表示にも対応しています。 REST API テキストデータやメタデータにプログラムからアクセスするための REST API が提供されています。外部のアプリケーションやツールとの連携が容易で、データの再利用を促進します。 レスポンシブデザイン 生成される Web ページはレスポンシブデザインに対応しており、PC、タブレット、スマートフォンなど、さまざまなデバイスで適切に表示されます。 多言語・多文字体系対応 ラテン文字はもちろん、アラビア文字、漢字、デーヴァナーガリーなど、多様な文字体系に対応しています。右から左に書く言語(RTL)もサポートしています。 導入方法 TEI Publisher は eXist-db 上で動作します。Docker を使った導入が推奨されています。 docker run -p 8080:8080 existdb/teipublisher:latest 起動後、ブラウザで http://localhost:8080/exist/apps/tei-publisher/ にアクセスすると、TEI Publisher のインターフェースが表示されます。サンプルのテキストが含まれているため、すぐに機能を試すことができます。 ...

TEI/XMLサイトをVercelで高速デプロイ:XSLT変換をsaxon-jsで自動化する

TEI/XMLサイトをVercelで高速デプロイ:XSLT変換をsaxon-jsで自動化する

はじめに TEI (Text Encoding Initiative) に準拠したXMLデータをXSLTでHTMLに変換し、Webで公開する構成は、デジタルヒューマニティーズの分野で広く使われています。 従来、ブラウザのクライアントサイドXSLT変換(<?xml-stylesheet?>やJavaScriptによるXSLTProcessor)でXMLを表示するケースが多いですが、この方式にはいくつかの課題があります。 ページを開くたびにブラウザがXSLT変換を実行するため、表示が遅い SEO・クローラー対応が難しい ブラウザごとのXSLT実装差異 本記事では、Vercelのビルド時にXML→HTML変換を自動実行し、生成済みHTMLを静的配信する方法を紹介します。 構成 project/ ├── docs/ # Vercelの出力ディレクトリ │ ├── index.html # トップページ │ └── data/ │ ├── *.xsl # XSLTスタイルシート │ ├── *.sef.json # コンパイル済みスタイルシート │ ├── *.xml # TEI/XMLソース │ └── *.html # 生成されるHTML(ビルド時生成) ├── build.js # ビルドスクリプト ├── package.json └── vercel.json Node.jsでのXSLT処理ライブラリ比較 Vercelのビルド環境ではネイティブツール(xsltproc等)が使えないため、Node.jsのXSLTライブラリを使う必要があります。以下の3つを検証しました。 xsltproc(参考:ローカル環境) macOSに標準搭載されているC言語実装のXSLTプロセッサです。 xsltproc docs/data/main.xsl docs/data/劉興我本巻一.xml > docs/data/劉興我本巻一.html 一瞬で完了しますが、Vercelのビルド環境では利用できません(apt-getが使えない)。 xslt-processor(純JavaScript実装) npm install xslt-processor GoogleのAJAXSLT(2005年)をベースにES2015+に更新したライブラリです。ブラウザにXSLTサポートがなかった時代のpolyfillが起源であり、1400行程度のXMLファイルの変換でも数分以上かかり、実用に堪えませんでした。 遅い理由は以下の通りです。 XPath式を実行時に毎回パース・評価する(キャッシュや事前コンパイルの仕組みがない) 最適化戦略がない設計のため、XPath評価が累積的に重くなる 純JavaScriptのDOM実装による木構造走査のオーバーヘッド saxon-js(Saxonica社製) npm install saxon-js xslt3 XSLT 3.0仕様の編集者であるMichael Kayが率いるSaxonica社が開発した高性能XSLTプロセッサです。最大の特徴は事前コンパイル方式にあります。 ...

TEI/XMLサイトをVercelで高速デプロイ:XSLT変換をsaxon-jsで自動化する

TEI/XMLサイトをVercelで高速デプロイ:XSLT変換をsaxon-jsで自動化する

はじめに TEI (Text Encoding Initiative) に準拠したXMLデータをXSLTでHTMLに変換し、Webで公開する構成は、デジタルヒューマニティーズの分野で広く使われています。 従来、ブラウザのクライアントサイドXSLT変換(<?xml-stylesheet?>やJavaScriptによるXSLTProcessor)でXMLを表示するケースが多いですが、この方式にはいくつかの課題があります。 ページを開くたびにブラウザがXSLT変換を実行するため、表示が遅い SEO・クローラー対応が難しい ブラウザごとのXSLT実装差異 本記事では、Vercelのビルド時にXML→HTML変換を自動実行し、生成済みHTMLを静的配信する方法を紹介します。 構成 project/ ├── docs/ # Vercelの出力ディレクトリ │ ├── index.html # トップページ │ └── data/ │ ├── main.xsl # XSLTスタイルシート │ ├── main.sef.json # コンパイル済みスタイルシート │ ├── source.xml # TEI/XMLソース │ └── source.html # 生成されるHTML(ビルド時生成) ├── build.js # ビルドスクリプト ├── package.json └── vercel.json Node.jsでのXSLT処理ライブラリ比較 Vercelのビルド環境ではネイティブツール(xsltproc等)が使えないため、Node.jsのXSLTライブラリを使う必要があります。以下の3つを検証しました。 xsltproc(参考:ローカル環境) macOSに標準搭載されているC言語実装のXSLTプロセッサです。 xsltproc docs/data/main.xsl docs/data/source.xml > docs/data/source.html 一瞬で完了しますが、Vercelのビルド環境では利用できません(apt-getが使えない)。 xslt-processor(純JavaScript実装) npm install xslt-processor GoogleのAJAXSLT(2005年)をベースにES2015+に更新したライブラリです。ブラウザにXSLTサポートがなかった時代のpolyfillが起源であり、1400行程度のXMLファイルの変換でも数分以上かかり、実用に堪えませんでした。 遅い理由は以下の通りです。 XPath式を実行時に毎回パース・評価する(キャッシュや事前コンパイルの仕組みがない) 最適化戦略がない設計のため、XPath評価が累積的に重くなる 純JavaScriptのDOM実装による木構造走査のオーバーヘッド saxon-js(Saxonica社製) npm install saxon-js xslt3 XSLT 3.0仕様の編集者であるMichael Kayが率いるSaxonica社が開発した高性能XSLTプロセッサです。最大の特徴は事前コンパイル方式にあります。 ...

DTS (Distributed Text Services) 1.0 正式リリースへの対応 ― TEI/XMLテキストAPIの仕様更新記録

はじめに 2026年2月、テキストコレクションへの標準的なアクセス手段を提供するAPI仕様「Distributed Text Services (DTS)」のv1.0が正式にリリースされました。 本記事では、DTS 1-alpha に基づいて構築していた校異源氏物語テキストDB用APIを、DTS 1.0に対応させた際の変更点を整理します。 https://github.com/distributed-text-services/specifications/releases/tag/v1.0 DTS とは DTS は、TEI/XMLなどのテキストコレクションに対する標準的なアクセスAPIを定める仕様です。以下の4つのエンドポイントで構成されます。 エンドポイント 役割 Entry Point APIの各エンドポイントURLを返す Collection テキスト間のナビゲーション(コレクション・リソースの一覧) Navigation テキスト内のナビゲーション(引用構造の探索) Document テキスト本体の取得(TEI/XMLの全体または一部) 対象プロジェクト 校異源氏物語テキストDBのDTS API実装(TypeScript/Express.js)です。 本番: https://dts-typescript.vercel.app/api/v2/dts ソースコード: https://github.com/nakamura196/dts-typescript 1-alpha から 1.0 への主な変更点 1. JSON-LD Context URLの変更 最も基本的な変更は、JSON-LDコンテキストファイルのURLです。 - "@context": "https://distributed-text-services.github.io/specifications/context/1-alpha1.json" + "@context": "https://dtsapi.org/context/v1.0.json" ドメインが distributed-text-services.github.io から dtsapi.org に変わりました。これは仕様の正式公開に伴い、永続的なURLが割り当てられたことを意味します。 2. dtsVersion の更新 - "dtsVersion": "1-alpha" + "dtsVersion": "1.0" 全エンドポイントのレスポンスに含まれる dtsVersion フィールドを更新します。 3. URI Template の全パラメータ記載 1-alphaでは一部のパラメータのみ記載していましたが、1.0ではAPIが受け付ける全パラメータをURI templateに含める必要があります。 Entry Point のレスポンス例: ...

DOCX → TEI/XML 変換ツールに CETEIcean を使ったプレビュー機能を追加した

DOCX → TEI/XML 変換ツールに CETEIcean を使ったプレビュー機能を追加した

はじめに 以前の記事で、DOCX → TEI/XML 変換ツールを紹介しました。TEI Garage API を使ってブラウザだけで Word 文書を TEI/XML に変換できるツールです。 公開後、利用者の方から「変換されたタグが想定どおりに機能するかを視覚的に確認したい」というフィードバックをいただきました。XML のシンタックスハイライト表示だけでは、見出し・注釈・リスト・テーブルなどが実際にどのようにレンダリングされるか確認が難しいためです。 そこで、CETEIcean を使った TEI プレビュー機能を追加しました。 デモサイト: https://tei-converter.pages.dev/ CETEIcean とは CETEIcean は、TEI Consortium が開発している JavaScript ライブラリです。TEI/XML を HTML5 カスタム要素(Custom Elements) に変換し、ブラウザ上でそのまま表示できます。 通常、TEI/XML をブラウザで表示するには XSLT で HTML に変換する必要がありますが、CETEIcean は Web Components の仕組みを利用して、TEI の要素名をそのままカスタム要素として登録します。例えば <p> は <tei-p> に、<head> は <tei-head> に変換されます。 これにより、CSS だけで TEI 要素のスタイルを定義でき、サーバサイドの変換処理が不要になります。 追加した機能 XML / プレビュー タブ切り替え 変換結果の表示エリアに 「XML」と「プレビュー」の2つのタブを追加しました。 XML タブ: 従来どおりのシンタックスハイライト付き XML 表示 プレビュータブ: CETEIcean によるレンダリング結果 タブをクリックするだけで切り替えられます。 ...

XSLT処理を5倍高速化:Saxon-JSからSaxon-HEへの移行

まとめ TEI XML → HTML変換において、npx xslt3(Saxon-JS)からJava Saxon-HEへ切り替えたところ、ビルド時間が1分48秒から23秒に短縮された(約5倍の高速化)。 背景 校異源氏物語テキストDBは、源氏物語のデジタルエディションで、54巻分のTEI XMLファイルを持つ。ビルドスクリプト(Python)が各XMLをHTMLに変換するため、npx xslt3を54回呼び出していた。 python3 scripts/prebuild.py xsl # 全54巻のXSLT処理 この処理がビルドパイプライン全体で最も時間のかかるステップだった。 ベンチマーク ファイルごとの比較 巻 文字数 npx xslt3 (JS) saxon (Java) 高速化率 01 桐壺 11,240 1.8秒 1.1秒 1.6倍 34 若菜上 46,230 4.9秒 0.4秒 12倍 ファイルが大きいほど改善幅が大きい。JVM起動コスト(約1秒)を差し引くと、実際の変換処理は桁違いに速い。 合計(全54巻) npx xslt3 (Saxon-JS): 1分48秒 saxon (Saxon-HE): 23秒 移行手順 ローカル環境(macOS) brew install saxon ビルドスクリプト SAXON_JAR環境変数 → saxonコマンド → npx xslt3の順にフォールバックするヘルパーを追加した。 def xslt_cmd(xsl, src, dst): """Return XSLT command, preferring Saxon-HE over npx xslt3.""" saxon_jar = os.environ.get('SAXON_JAR') if saxon_jar: return ['java', '-jar', saxon_jar, f'-xsl:{xsl}', f'-s:{src}', f'-o:{dst}'] if shutil.which('saxon'): return ['saxon', f'-xsl:{xsl}', f'-s:{src}', f'-o:{dst}'] return ['npx', 'xslt3', f'-xsl:{xsl}', f'-s:{src}', f'-o:{dst}'] GitHub Actions Node.js + xslt3をJava + Saxon-HE jarに置き換えた。 ...

TEI Garage APIを使って、DOCX → TEI/XML 変換ツールをブラウザだけで作った

TEI Garage APIを使って、DOCX → TEI/XML 変換ツールをブラウザだけで作った

はじめに TEI (Text Encoding Initiative) は、人文学分野のテキストをデジタルで構造化するための国際標準です。図書館・博物館・学術研究などで利用されていますが、TEI/XML を直接書くにはマークアップの知識が必要で、導入のハードルが高いのが実情です。 そこで活用されるのが、Microsoft Word (.docx) から TEI/XML への変換ツールです。代表的なものに TEI Garage(旧 OxGarage)がありますが、多機能ゆえに UI がやや複雑です。今回、DOCX → TEI/XML の変換に特化した、シンプルなブラウザベースのツールを作成しました。 https://github.com/nakamura196/tei-converter デモサイト: https://tei-converter.pages.dev/ 仕組み TEI Garage は REST API を公開しており、以下のエンドポイントに DOCX ファイルを POST するだけで TEI/XML が返ってきます。 POST https://teigarage.tei-c.org/ege-webservice/Conversions/ docx:application:vnd.openxmlformats-officedocument.wordprocessingml.document/ TEI:text:xml/ 本ツールはこの API を呼び出すフロントエンドです。変換処理自体は TEI Consortium が運営するサーバ上で行われます。 主な機能 ドラッグ & ドロップ .docx ファイルをブラウザにドラッグ & ドロップするだけでアップロードできます。クリックしてファイルを選択することも可能です。 整形済み XML プレビュー 変換結果はインデント付きで整形され、シンタックスハイライト付きで表示されます。タグ名、属性名、属性値がそれぞれ色分けされるため、構造を把握しやすくなっています。 コピー & ダウンロード 結果をワンクリックでクリップボードにコピーしたり、.xml ファイルとしてダウンロードしたりできます。 サンプル DOCX 内蔵 「サンプル .docx で試す」をクリックするだけで、内蔵のサンプルファイルで動作を確認できます。サンプルのダウンロードも可能です。 ...

Hypothes.is APIでWebアノテーションをエクスポートしてTEI/XMLに変換する

Hypothes.is APIでWebアノテーションをエクスポートしてTEI/XMLに変換する

はじめに Hypothes.isは、Webページ上にハイライトやコメントを付けられるオープンソースのアノテーションツールです。ブラウザ拡張やJavaScriptの埋め込みで手軽に使えますが、蓄積したアノテーションをバックアップしたい、あるいはTEI/XMLなど別の形式で活用したいケースもあります。 本記事では、Hypothes.is APIを使ってアノテーションをエクスポートし、TEI/XMLに変換する方法を紹介します。 APIキーの取得 Hypothes.isにログイン Developer settings にアクセス 「Generate your API token」でAPIキーを生成 取得したキーを.envファイルに保存します。 cp .env.example .env # .env を編集してAPIキーを設定 HYPOTHESIS_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx アノテーションのエクスポート APIの基本 Hypothes.is APIのベースURLは https://api.hypothes.is/api です。認証はAuthorization: Bearer <API_KEY>ヘッダーで行います。 主要なエンドポイント: エンドポイント 用途 GET /api/profile 認証ユーザーのプロフィール取得 GET /api/search アノテーション検索 GET /api/annotations/{id} 個別アノテーション取得 スクリプト エクスポートからTEI/XML変換までを1つのスクリプト hypothes_export.py にまとめています。 https://github.com/nakamura196/hypothes-export/blob/main/hypothes_export.py 以下、主要な処理を抜粋して説明します。 .envの読み込みとAPI呼び出し def load_env(): env_path = Path(__file__).parent / ".env" with open(env_path) as f: for line in f: line = line.strip() if line and not line.startswith("#") and "=" in line: k, v = line.split("=", 1) os.environ[k.strip()] = v.strip() def api_get(endpoint, params=None): api_key = os.environ["HYPOTHESIS_API_KEY"] url = f"https://api.hypothes.is/api/{endpoint}" if params: url += "?" + urllib.parse.urlencode(params) req = urllib.request.Request(url) req.add_header("Authorization", f"Bearer {api_key}") with urllib.request.urlopen(req) as resp: return json.loads(resp.read().decode()) 全アノテーションの取得(ページネーション対応) Search APIは1リクエストあたり最大200件なので、offsetをずらして全件取得します。 ...

OpenITI mARkdownからTEI XMLへの自動変換ツール「oitei」を試す

OpenITI mARkdownからTEI XMLへの自動変換ツール「oitei」を試す

はじめに イスラーム圏の歴史テキストを扱う OpenITI(Open Islamicate Texts Initiative) プロジェクトでは、TEI/XMLの代わりに mARkdown という軽量記法でテキストをタグ付けできます。 TEI/XMLは構造化の国際規格として強力ですが、特にアラビア語のような右から左に書く言語(RTL)では、XMLタグとの混在でエディタ上の表示が乱れるという問題があります。mARkdownはこの課題を解決する記法です。 本記事では、mARkdownで書かれたテキストを TEI XMLに自動変換 するPythonツール oitei を実際に動かしてみます。 oiteiとは OpenITI mARkdown → TEI XML の変換ライブラリ(Python) OpenITI TEI Schema に準拠したXMLを出力 PyPIで公開されており pip install で導入可能 依存ライブラリ: oimdp(mARkdownパーサー)、lxml https://github.com/OpenITI/oitei インストール pip install oitei Python 3.8以上が必要です。oimdp(OpenITI mARkdown Parser)と lxml が依存関係として自動インストールされます。 OpenITI mARkdownの記法 mARkdownファイルは以下の3部構成です。 マジックバリュー (1行目): ######OpenITI# メタデータ : #META# で始まる行 本文 : #META#Header#End# の後に記述 主なタグ 記法 意味 `### ` `### ### $ 伝記エントリ # 段落の開始 @P02 名前 人物名(後続2語を含む) @T11 地名 地名(後続1語を含む) @YB732 誕生年(ヒジュラ暦732年) @YD808 没年(ヒジュラ暦808年) %~% 詩行(hemistich)の区切り 固有表現タグ(@P, @T 等)の後ろの 2桁の数字 は、1桁目がエンティティ番号、2桁目が「後続する何単語を名前に含むか」を指定します。例えば @P02 Ibn Khaldun は「後続2語(Ibn Khaldun)を人名として含む」という意味です。 ...

ODD編集Tips:その1

ODD編集Tips:その1

要素の属性を特定のものだけに制限する TEIのデフォルトでは、要素は多くの属性クラス(att.global、att.datableなど)を継承しており、多数の属性が使用可能です。特定の属性のみを許可したい場合は、以下のように設定します。 例: persNameでxml:idとcorrespのみを許可 <elementSpec ident="persName" mode="change"> <classes mode="change"> <!-- 属性クラスを削除(モデルクラスは維持) --> <memberOf key="att.global" mode="delete"/> <memberOf key="att.cmc" mode="delete"/> <memberOf key="att.datable" mode="delete"/> <memberOf key="att.editLike" mode="delete"/> <memberOf key="att.personal" mode="delete"/> <memberOf key="att.typed" mode="delete"/> </classes> <attList> <attDef ident="xml:id" mode="add" usage="opt"> <desc>要素の一意な識別子</desc> <datatype> <dataRef name="ID"/> </datatype> </attDef> <attDef ident="corresp" mode="add" usage="opt"> <desc>関連する人物情報へのリンク</desc> <datatype> <dataRef key="teidata.pointer"/> </datatype> </attDef> </attList> </elementSpec> ポイント <classes mode="change">を使用: mode="replace"で空にすると、モデルクラスも削除され要素自体が使えなくなる 属性クラスを個別に削除 : <memberOf key="att.xxx" mode="delete"/>で不要な属性クラスを削除 必要な属性を追加 : <attDef ident="xxx" mode="add">で許可したい属性を定義 注意点 要素がどの属性クラスに属しているかは、TEI Guidelinesで確認できる att.globalを削除するとxml:id、xml:langなども使えなくなるため、必要に応じて個別に追加する 要素に属性を追加する 既存の属性クラスを維持したまま、新しい属性を追加する場合: <elementSpec ident="pb" mode="change"> <attList> <attDef ident="facs" mode="add" usage="opt"> <desc>原本画像へのリンク</desc> <datatype> <dataRef key="teidata.pointer"/> </datatype> </attDef> </attList> </elementSpec> この場合、既存の属性クラスはそのまま維持され、facs属性が追加されます。

TEI ODDによるIIIF対応ファクシミリ記述の制約設計

TEI ODDによるIIIF対応ファクシミリ記述の制約設計

はじめに TEI(Text Encoding Initiative)でデジタル画像のメタデータを記述する際、facsimile要素を使用します。特にIIIF(International Image Interoperability Framework)対応のデジタルアーカイブでは、マニフェストやキャンバス、Image APIへの参照を適切に記述することが重要です。 本記事では、ODD(One Document Does it all)を使用して、ファクシミリ記述に必要な制約をスキーマとして定義する方法を紹介します。 準拠するガイドライン 本ODDは、日本語TEIガイドラインで紹介されている「IIIF画像とのリンク」仕様をベースにしています: IIIF画像とのリンク(2024年度版)- TEI-EAJ このガイドラインに準拠したデータを作成することで、TEI Viewer for EAJでの画像表示が可能になります。TEI Viewerは、TEIテキストとIIIF画像を連携して表示できるビューアであり、facsimile要素の情報を利用してテキストと画像の対応付けを行います。 設計目標 以下の要件を満たすスキーマを設計しました: 必須情報の明確化 : 画像の座標情報や識別子など、最低限必要な情報を必須属性として定義 IIIF対応 : マニフェスト、キャンバス、Image APIへの参照をオプショナルに記述可能 再利用性 : 独立したODDファイルとして、複数プロジェクトで共有可能 ビューア互換性 : TEI Viewer for EAJでの表示に必要な情報を確実に記録 最小限の記述例 <facsimile sameAs="https://example.org/iiif/manifest.json"> <surface ulx="0" uly="0" lrx="5600" lry="4000" xml:id="p1"> <graphic sameAs="https://example.org/image/001.tif"/> </surface> </facsimile> 完全な記述例(IIIF参照を含む) <facsimile sameAs="https://example.org/iiif/manifest.json"> <surface ulx="0" uly="0" lrx="5600" lry="4000" sameAs="https://example.org/canvas/p1" xml:id="p1"> <graphic url="https://example.org/image/001.tif/full/full/0/default.jpg" sameAs="https://example.org/image/001.tif"/> </surface> </facsimile> ODD定義の解説 1. facsimile要素 <elementSpec ident="facsimile" mode="change"> <desc>ファクシミリ画像情報。IIIFマニフェストへの参照を含む。</desc> <classes mode="replace"/> <content> <elementRef key="surface" minOccurs="1" maxOccurs="unbounded"/> </content> <attList mode="replace"> <attDef ident="sameAs" mode="replace" usage="opt"> <desc>IIIFマニフェストへの参照URL</desc> <datatype> <dataRef key="teidata.pointer"/> </datatype> </attDef> </attList> </elementSpec> ポイント : ...

ODD Chain チュートリアル

ODD Chain チュートリアル

TEI ODDの「チェーン」機能を使ってスキーマをカスタマイズする方法を学ぶチュートリアルです。 ODD Chainとは ODD chainには2つの方式があります: 1. 継承型(縦のチェーン) source属性で親ODDを参照し、カスタマイズを継承します。 TEI_all → ベースODD → 派生ODD → さらなる派生... 2. 組み合わせ型(横のチェーン) specGrpとspecGrpRefを使って、複数のODDを統合します。 ヘッダー用ODD ─┬─→ 統合されたスキーマ 本文用ODD ─────┘ フォルダ構成 tutorials/ ├── 01-inheritance/ # 継承型の例 │ ├── base.odd # ベースとなるODD │ └── derived.odd # base.oddを継承する派生ODD ├── 02-chain/ # 組み合わせ型の例 │ ├── header-specs.odd # ヘッダー関連のカスタマイズ │ ├── text-specs.odd # 本文関連のカスタマイズ │ ├── main.odd # 統合用メインODD │ └── merge-specs.xsl # specGrpRefを展開するXSLT ├── output/ # 生成されたファイル │ ├── base.rng # 01のベースODDから生成 │ ├── base.html # 同上のHTMLドキュメント │ ├── derived.rng # 01の派生ODDから生成 │ ├── derived.html # 同上のHTMLドキュメント │ ├── combined.rng # 02の統合ODDから生成 │ ├── combined.html # 同上のHTMLドキュメント │ └── intermediate/ # 中間ファイル │ ├── base.compiled.odd │ ├── derived.compiled.odd │ ├── combined.merged.odd │ └── combined.compiled.odd ├── build.sh # ビルドスクリプト └── README.md # このファイル 前提条件 Saxon(XSLT 2.0プロセッサ) TEI Stylesheets(../scripts/Stylesheetsにインストール済み) ビルド方法 cd tutorials ./build.sh 生成されるファイル ソースODD RNG HTML 01-inheritance/base.odd output/base.rng output/base.html 01-inheritance/derived.odd output/derived.rng output/derived.html 02-chain/main.odd(統合後) output/combined.rng output/combined.html 各ファイルの説明 01-inheritance(継承型) base.odd ベースとなるODD。最小限のモジュールと基本的なカスタマイズを含む。 ...

TEI古典籍ビューワをカスタマイズして判読不能箇所(gap)を表示する

TEI古典籍ビューワをカスタマイズして判読不能箇所(gap)を表示する

はじめに 東アジアの古典籍をデジタル化する際、TEI(Text Encoding Initiative)ガイドラインに準拠したXMLでマークアップすることが一般的になっています。一般財団法人人文情報学研究所が開発した「TEI古典籍ビューワ」は、このようなTEI/XMLファイルをブラウザで簡単に表示できる便利なツールです。 公式サイト: https://tei.dhii.jp/teiviewer4eaj Web版: https://candra.dhii.jp/nagasaki/tei/tei_viewer/ 今回、このビューワをカスタマイズして、判読不能箇所を示す<gap>タグの表示に対応しました。本記事では、そのカスタマイズ方法を紹介します。 デモ: https://nakamura196.github.io/custom-tei-viewer/?file=sample_gap.xml&height=1800 課題:gapタグが表示されない 古典籍のデジタル化において、虫損や破損などにより判読できない箇所は<gap>タグでマークアップします。 <gap reason="illegible" quantity="2" unit="character"/> しかし、標準のTEI古典籍ビューワでは、このタグが適切に表示されません。そこで、判読不能な文字数分の黒四角(■)を表示し、マウスホバーで理由を確認できるようにカスタマイズしました。 カスタマイズの方針 TEI古典籍ビューワは以下のファイル構成になっています。 ├── index.html ├── app.min.js ← ビューワ本体(minify済み) ├── app.min.css ├── app_conf.js ← 設定ファイル └── lib/ ← 依存ライブラリ app.min.jsを直接編集すると、本体のアップデート時に変更が失われてしまいます。そこで、app_conf.jsのみを編集することで、本体との互換性を保ちながらカスタマイズを実現しました。 実装方法 1. MutationObserverによるDOM監視 TEI古典籍ビューワはXMLをパースしてDOMに変換します。この変換後のタイミングで<gap>タグを処理するため、MutationObserverを使用してDOM変更を監視します。 // MutationObserverでDOM変更を監視 const observer = new MutationObserver(mutations => { mutations.forEach(mutation => { mutation.addedNodes.forEach(node => { if (node.nodeType === Node.ELEMENT_NODE) { processGapElements(node); } }); }); }); // body_resultの監視を開始 document.addEventListener('DOMContentLoaded', () => { const bodyResult = document.getElementById('body_result'); if (bodyResult) { observer.observe(bodyResult, { childList: true, subtree: true }); } }); 2. gapタグの処理 <gap>タグを検出したら、quantity属性の値に応じて黒四角を表示し、reason属性をツールチップとして設定します。 function processGapElements(container) { const gaps = container.querySelectorAll('gap, .gap, [data-original-tag-name="gap"]'); gaps.forEach(gap => { // 既に処理済みの場合はスキップ if (gap.dataset.gapProcessed) return; gap.dataset.gapProcessed = 'true'; // 属性から値を取得 const quantity = parseInt(gap.getAttribute('quantity') || '1', 10); const reason = gap.getAttribute('reason') || ''; // ■をquantity分だけ生成 const placeholder = '■'.repeat(quantity); gap.textContent = placeholder; // ツールチップの設定(日本語化) const reasonMap = { 'illegible': '判読不能', 'damage': '破損', 'worm': '虫損', 'omitted': '省略', 'cancelled': '抹消', 'lost': '欠損' }; const reasonText = reasonMap[reason] || reason; if (reasonText) { gap.setAttribute('title', reasonText); } gap.style.color = '#333'; gap.style.cursor = 'help'; }); } ポイント:属性の取得方法 TEI古典籍ビューワがXMLをHTMLに変換する際、属性の扱いは要素によって異なります。<gap>タグの場合、XML属性がそのまま保持されるため、getAttribute()で直接取得できます。 ...

TEI Processing Modelで実現する宣言的なマルチフォーマット変換

TEI Processing Modelで実現する宣言的なマルチフォーマット変換

はじめに TEI (Text Encoding Initiative) は人文学テキストのデジタル化において広く使われている標準規格です。本記事では、TEI P5で導入された Processing Model という機能を使って、TEI XMLから複数のフォーマット(HTML、LaTeX/PDF、EPUB3)への変換を実現した事例を紹介します。 https://www.tei-c.org/Vault/P5/3.0.0/doc/tei-p5-doc/en/html/TD.html#TDPM 対象プロジェクトは「校異源氏物語」で公開されているテキストを例とします。 https://kouigenjimonogatari.github.io/ 背景 これまで、以下の記事で紹介したように、変換処理を個別に行ってきました。 ODD/RNGファイルのカスタマイズによる、使用するタグの限定 XSLTを用いたHTMLへの変換 XSLTを用いたTeX/PDFへの変換 EPUBへの変換 それぞれの取り組みにおいて、個別の変換ルールなどを記載したファイルを作成する必要があり、その煩雑さが課題となっていました。 Processing Modelとは Processing Modelは、TEI要素の変換ルールを宣言的 に記述する仕組みです。従来は各出力フォーマット用に個別のXSLTを書く必要がありましたが、Processing Modelを使うことで: ODDファイル内で変換ルールを定義 できる 複数の出力フォーマット に対応可能(web、latex、epubなど) スキーマと変換ルールを一元管理 できる Processing Modelの構造 <elementSpec ident="persName" mode="change"> <desc>Personal name</desc> <model> <!-- HTML output --> <modelSequence output="web"> <model behaviour="inline"> <outputRendition>span</outputRendition> <desc>Inline span for person name</desc> </model> </modelSequence> <!-- EPUB3 output --> <modelSequence output="epub"> <model behaviour="inline"> <outputRendition>span</outputRendition> <desc>Inline span for person name in EPUB3</desc> </model> </modelSequence> <!-- LaTeX output --> <modelSequence output="latex"> <model behaviour="inline"> <outputRendition>\person</outputRendition> <desc>Custom LaTeX command for person names</desc> </model> </modelSequence> </model> </elementSpec> 主な要素: ...

TEI/XMLファイルをGitHubで公開する手順書

TEI/XMLファイルをGitHubで公開する手順書

はじめに この記事では、TEI(Text Encoding Initiative)形式のXMLファイルをGitHubにアップロードし、誰でも参照できるURLを作成する手順を説明します。 TEI/XMLは、歴史文献や文学作品などのテキストを構造的に記述するための国際標準形式です。GitHubを使うことで、あなたの研究データを世界中の研究者と共有できるようになります。 必要なもの パソコン(Windows、Mac、Linuxのいずれか) インターネット接続 TEI/XMLファイル(すでにお持ちのもの) メールアドレス(GitHubアカウント作成用) サンプルファイルについて TEI/XMLファイルをお持ちでない方は、以下の『校異源氏物語』のTEI/XMLファイルを練習用として使用できます: サンプルファイルURL : https://raw.githubusercontent.com/kouigenjimonogatari/kouigenjimonogatari.github.io/master/tei/01.xml このファイルをダウンロードする方法: 上記URLをブラウザで開く 右クリック→「名前を付けて保存」を選択 ファイル名を「koukin_genji_01.xml」などに設定して保存 ステップ1:GitHubアカウントの作成 1-1. GitHubのウェブサイトにアクセス ブラウザ(Chrome、Firefox、Safari等)を開きます アドレスバーに https://github.com と入力してEnterキーを押します 1-2. アカウント作成 右上の「Sign up」ボタンをクリックします 以下の情報を入力します: メールアドレス :普段お使いのメールアドレス パスワード :安全なパスワード(8文字以上、数字と記号を含む) ユーザー名 :他の人と重複しない名前(例:yamada-taro2024) 「Create account」をクリックします メールに届いた認証コードを入力します 💡 ヒント : ユーザー名は後から変更できないので、慎重に選びましょう。研究者として使う場合は、実名に基づいた名前がおすすめです。 ステップ2:新しいリポジトリの作成 リポジトリとは、ファイルを保管する「プロジェクトフォルダ」のようなものです。 2-1. リポジトリ作成画面へ GitHubにログインした状態で、右上の「+」マークをクリックします 「New repository」を選択します 2-2. リポジトリの設定 以下の項目を入力・選択します: Repository name(リポジトリ名) 英数字とハイフン(-)が使えます 例:tei-xml-collection、medieval-texts-tei Description(説明)※任意 プロジェクトの簡単な説明 例:「中世文献のTEI/XMLファイル集」 Public/Private(公開設定) Public を選択:誰でも閲覧可能(推奨) Private:招待した人のみ閲覧可能 Initialize this repository with:(初期化オプション) ✅ Add a README file にチェックを入れる その他はそのままで大丈夫です 緑色の「Create repository」ボタンをクリックします ステップ3:TEI/XMLファイルのアップロード 3-1. アップロード画面へ リポジトリが作成されると、ファイル一覧画面が表示されます 「Add file」ボタンをクリックします 「Upload files」を選択します 3-2. ファイルのアップロード 方法A:ドラッグ&ドロップ エクスプローラー(Windows)またはFinder(Mac)でTEI/XMLファイルがある場所を開きます アップロードしたいファイルを選択します(複数選択可) ブラウザの点線枠内にドラッグ&ドロップします 方法B:ファイル選択 「choose your files」をクリックします ファイル選択ダイアログでTEI/XMLファイルを選択します 「開く」をクリックします 実例:『校異源氏物語』のTEI/XMLファイルをアップロード サンプルファイルを使った具体例: ...

TEI ODDファイルのカスタマイゼーション:NDL古典籍OCRの事例

TEI ODDファイルのカスタマイゼーション:NDL古典籍OCRの事例

はじめに TEI (Text Encoding Initiative) は、人文学研究におけるテキストのデジタル化と共有のための国際標準です。本記事では、NDL古典籍OCR-Liteアプリケーションの出力形式に合わせてTEI ODDファイルをカスタマイズした過程を紹介します。 ODD (One Document Does it all) は、TEIスキーマをカスタマイズするための仕組みで、必要な要素と属性だけを含む独自のスキーマを定義できます。 背景:NDL古典籍OCR-Liteアプリケーションの開発 NDL古典籍OCR-Liteの出力結果をTEI/XMLで出力するアプリケーションを作成しています。このアプリケーションは、日本の古典籍をOCR処理し、その結果を標準的なTEI形式で出力することを目的としています。 出力されるTEI XMLには以下の情報を含めることにしました: テキスト情報 : OCRで認識した文字列 レイアウト情報 : 各行の座標情報(バウンディングボックス) 画像参照 : IIIF (International Image Interoperability Framework) 対応の画像URL メタデータ : 文書タイトル、処理情報など このアプリケーションで使用するスキーマをODDで記述してみました。以下、そのカスタマイゼーション過程を紹介します。 カスタマイゼーションのアプローチ 1. 初期アプローチ:標準モジュールの利用 最初は、TEIの標準モジュールを利用してODDを作成しました: schemaSpec ident="ndl_koten_ocr" start="TEI" prefix="tei_"> moduleRef key="tei"/> moduleRef key="header" include="teiHeader fileDesc titleStmt publicationStmt sourceDesc"/> moduleRef key="core" include="p title name resp respStmt lb pb graphic"/> moduleRef key="textstructure" include="TEI text body"/> moduleRef key="transcr" include="facsimile surface zone"/> schemaSpec> include属性の重要性 moduleRef要素のinclude属性は、モジュールから特定の要素のみを選択的に含める重要な機能です: ...

TEI GarageのAPIを使用したODDからRNG/HTMLへの変換

TEI GarageのAPIを使用したODDからRNG/HTMLへの変換

はじめに TEI(Text Encoding Initiative)のODD(One Document Does it all)ファイルから、スキーマ(RNG)やドキュメント(HTML)を生成する作業は、TEIプロジェクトにおいて重要な工程です。本記事では、Roma(TEIのODDエディタ)が内部で使用しているTEI Garage APIの仕組みを解析し、スクリプトから直接APIを呼び出してODDを変換する方法を紹介します。 TEI Garageとは TEI Garageは、TEIコミュニティが提供するWebサービスで、様々なフォーマット間の変換を行うことができます。特にODDファイルの処理において、以下の機能を提供しています: ODD → Compiled ODD への変換 Compiled ODD → RELAX NG スキーマへの変換 ODD → HTML ドキュメントへの変換 その他多数のフォーマット変換 Romaの内部動作を解析 Romaのネットワークトラフィックを観察すると、以下のような変換チェーンを使用していることがわかりました: HTMLドキュメント生成の場合 ODD → ODDC (Compiled ODD) → TEI → xHTML 実際のAPIエンドポイント: https://teigarage.tei-c.org/ege-webservice/Conversions/ODD%3Atext%3Axml/ODDC%3Atext%3Axml/TEI%3Atext%3Axml/xhtml%3Aapplication%3Axhtml%2Bxml/conversion RNGスキーマ生成の場合 ODD → ODDC (Compiled ODD) → RELAXNG 実際のAPIエンドポイント: https://teigarage.tei-c.org/ege-webservice/Conversions/ODD%3Atext%3Axml/ODDC%3Atext%3Axml/relaxng%3Aapplication%3Axml-relaxng/conversion 変換パラメータの詳細 Romaは変換時に以下のようなXML形式のプロパティを送信しています: conversions> conversion index="0"> property id="oxgarage.getImages">falseproperty> property id="oxgarage.getOnlineImages">falseproperty> property id="oxgarage.lang">japroperty> property id="oxgarage.textOnly">falseproperty> property id="pl.psnc.dl.ege.tei.profileNames">defaultproperty> conversion> conversion index="1"> property id="oxgarage.getImages">falseproperty> property id="oxgarage.getOnlineImages">falseproperty> property id="oxgarage.lang">japroperty> property id="oxgarage.textOnly">trueproperty> property id="pl.psnc.dl.ege.tei.profileNames">defaultproperty> conversion> conversions> 各プロパティの意味: ...

RELAX NGとSchematronを組み合わせたTEI XMLスキーマの実装ガイド

RELAX NGとSchematronを組み合わせたTEI XMLスキーマの実装ガイド

! 人手で検証を行った後、AIが記事を執筆しました。 はじめに TEI(Text Encoding Initiative)XMLを編集する際、要素や属性の構造検証だけでなく、より複雑なビジネスルールの検証が必要になることがあります。本記事では、RELAX NG(RNG)とSchematronを組み合わせて、構造検証と内容検証の両方を実現する方法を、実際のプロジェクトで直面した課題を例に解説します。 解決したい課題 日本の古典文学テキストをTEI XMLで校訂する際、以下のような要求がありました: ID参照の動的検証 : corresp属性で参照するIDが、実際に文書内のwitness要素に存在することを検証したい Oxygen XML Editorでの補完機能 : 編集時にIDの候補を自動表示したい 複数ID参照のサポート : スペース区切りで複数のIDを指定可能にしたい 特定要素のみ参照を許可 : witness要素のIDのみを参照可能とし、person要素のIDが含まれる場合はエラーにしたい なぜRNG + Schematronなのか? RELAX NGの得意分野 要素・属性の構造定義 データ型の指定 基本的な内容モデルの定義 Schematronの得意分野 XPathベースの複雑な検証ルール 文書内の相互参照チェック カスタムエラーメッセージの提供 この2つを組み合わせることで、構造と内容の両面から厳密な検証が可能になります。 実装例 1. 基本的なRNGスキーマ構造 <?xml version="1.0" encoding="UTF-8"?> <grammar xmlns="http://relaxng.org/ns/structure/1.0" xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes" ns="http://www.tei-c.org/ns/1.0"> <!-- Schematron名前空間宣言 --> <sch:ns prefix="tei" uri="http://www.tei-c.org/ns/1.0"/> <!-- ここにSchematronルールを埋め込む --> <start> <ref name="TEI"/> </start> <!-- RNGによる構造定義 --> </grammar> 2. ID定義とanyURI型の活用 Oxygen XML Editorで自動補完を実現するために、anyURI型を使用します: ...