はじめに

イスラーム圏の歴史テキストを扱う 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. マジックバリュー (1行目): ######OpenITI#
  2. メタデータ : #META# で始まる行
  3. 本文 : #META#Header#End# の後に記述

主なタグ

記法意味
`###`
`###
### $伝記エントリ
#段落の開始
@P02 名前人物名(後続2語を含む)
@T11 地名地名(後続1語を含む)
@YB732誕生年(ヒジュラ暦732年)
@YD808没年(ヒジュラ暦808年)
%~%詩行(hemistich)の区切り

固有表現タグ(@P, @T 等)の後ろの 2桁の数字 は、1桁目がエンティティ番号、2桁目が「後続する何単語を名前に含むか」を指定します。例えば @P02 Ibn Khaldun は「後続2語(Ibn Khaldun)を人名として含む」という意味です。

サンプルファイルの作成

以下の内容で sample_markdown.md を作成します。

######OpenITI#

#META# Title: Sample Text for OpenITI mARkdown Demo
#META# Author: Demo Author
#META# Language: Arabic
#META#Header#End#

### | Chapter One: Introduction

# This is the first paragraph of the sample text. It demonstrates how OpenITI mARkdown works for tagging biographical and geographical information.

### $ Ibn Khaldun

# @P02 Ibn Khaldun was born in @T11 Tunis in @YB732 and died in @YD808 in @T11 Cairo . He wrote the Muqaddimah.

### || Section on Geography

# The city of @T11 Damascus was an important center of learning. Many scholars traveled from @T11 Baghdad to @T11 Damascus .

### $ Abu Bakr al-Razi

# @P03 Abu Bakr al-Razi was a renowned physician. He was born in @T11 Rayy and later moved to @T11 Baghdad . He died in @YD313 .

### | Chapter Two: Poetry

# The following is a sample verse:

# %~% The morning light shines on the desert sand %~% And caravan bells echo through the land

# This concludes our sample text.

変換の実行

import oitei

md = open("sample_markdown.md", "r").read()
tei_string = oitei.convert(md).tostring()

with open("sample_tei.xml", "w") as writer:
    writer.write(tei_string)

たった4行で変換が完了します。

変換結果

生成された TEI XML は以下の通りです。

<?xml version='1.0' encoding='UTF-8'?>
<TEI xmlns="http://www.tei-c.org/ns/1.0"
     xmlns:xi="http://www.w3.org/2001/XInclude">
  <teiHeader>
    <fileDesc>
      <titleStmt>
        <title/>
        <author/>
      </titleStmt>
      <publicationStmt>
        <publisher>Open Islamicate Texts Initiative (OpenITI)</publisher>
        <availability>
          <p>Creative Commons Attribution Non Commercial Share Alike
             4.0 International</p>
        </availability>
      </publicationStmt>
      <sourceDesc>
        <bibl/>
      </sourceDesc>
    </fileDesc>
    <profileDesc>
      <calendarDesc>
        <calendar xml:id="ah">
          <p>Anno Hegirae</p>
        </calendar>
      </calendarDesc>
    </profileDesc>
    <xenoData xml:space="preserve">
Title: Sample Text for OpenITI mARkdown Demo
Author: Demo Author
Language: Arabic
</xenoData>
  </teiHeader>
  <text>
    <body>
      <div>
        <head>Chapter One: Introduction</head>
        <p>
          <lb/>This is the first paragraph of the sample text. ...
        </p>
        <div type="biography" subtype="man">
          <head>Ibn Khaldun</head>
          <p>
            <lb/>
            <persName>Ibn Khaldun </persName> was born in
            T<placeName>unis </placeName> in
            <date type="birth" calendar="#ah" when-custom="732"/>
            and died in
            <date type="death" calendar="#ah" when-custom="808"/>
            in C<placeName>airo </placeName> .
            He wrote the Muqaddimah.
          </p>
        </div>
        <!-- ... 以下略 ... -->
      </div>
    </body>
  </text>
</TEI>

変換のポイント

mARkdownの各タグが適切なTEI要素に変換されています。

mARkdownTEI XML
`###` 章見出し
### $ 伝記<div type="biography" subtype="man">
@P02 Ibn Khaldun<persName>Ibn Khaldun</persName>
@T11 Tunis<placeName>unis</placeName>
@YB732<date type="birth" calendar="#ah" when-custom="732"/>
@YD808<date type="death" calendar="#ah" when-custom="808"/>
%~% 詩行区切り<caesura/>
#META# メタデータ<xenoData>

ヒジュラ暦の年号には自動的に calendar="#ah" が付与され、暦体系が明示されます。

日本語テキストへの適用

oiteiはイスラーム圏のテキスト向けに設計されていますが、日本語テキストにも適用できるか試してみます。

注意点:スペース区切りの問題

mARkdownの固有表現タグ(@P, @T 等)は、スペース区切りで「後続N語」 を名前として取り込む仕組みです。日本語はスペースで単語が区切られないため、工夫が必要です。

  • @P02 Ibn Khaldun → 後続2語 = “Ibn Khaldun” ✅(英語・アラビア語)
  • @P02 源 頼朝 → 後続2語 = “源” “頼朝” … だが <persName>源 頼朝</persName> にはなるものの不自然

対処法 : 日本語の名前はスペースなしで1語にまとめ、@P01(後続1語)を使います。

@P01 源頼朝    → <persName>源頼朝</persName> ✅
@T01 鎌倉      → <placeName>鎌倉</placeName> ✅

日本語サンプル

架空の人物・地名を使った単純な例で試します。

######OpenITI#

#META# Title: 日本語テキストサンプル
#META# Author: デモ著者
#META# Language: Japanese
#META#Header#End#

### | 第一章 人物紹介

# @P01 太郎 は @T01 東京 に住んでいる。

# @P01 花子 は @T01 京都 で生まれ、現在は @T01 大阪 に住んでいる。

### | 第二章 詩

# 以下はサンプルの詩である。

# %~% 春の風が街を吹き抜け %~% 桜の花びらが舞い散る

# これでサンプルテキストは終わりである。

日本語の変換結果

<div>
  <head>第一章 人物紹介</head>
  <p>
    <lb/>
    <persName>太郎 </persName><placeName>東京 </placeName> に住んでいる。
  </p>
  <p>
    <lb/>
    <persName>花子 </persName><placeName>京都 </placeName> で生まれ、
    現在は <placeName>大阪 </placeName> に住んでいる。
  </p>
</div>
<div>
  <head>第二章 詩</head>
  <p>
    <lb/>以下はサンプルの詩である。
  </p>
  <lg>
    <l>
      <caesura/> 春の風が街を吹き抜け
      <caesura/> 桜の花びらが舞い散る
    </l>
  </lg>
</div>

人物名・地名・詩行がTEI要素に変換されており、このXMLも tei_all.rng でバリデーションに通ることを確認しました。

!

oiteiはイスラーム圏テキスト向けのツールであるため、以下の点に注意が必要です。

  • teiHeadercalendar="#ah"(ヒジュラ暦)が固定で出力される
  • publisher が “Open Islamicate Texts Initiative” 固定
  • 日本語で使う場合、固有表現タグの前後にスペースが必要

本格的に日本語テキストのTEI化を行う場合は、oiteiの出力をベースにヘッダ等を修正するか、別のツールの利用を検討してください。

TEIスキーマによるバリデーション

生成されたXMLがTEI規格に適合しているか検証します。

# TEI Allスキーマをダウンロード
curl -sL -o tei_all.rng \
  https://tei-c.org/release/xml/tei/custom/schema/relaxng/tei_all.rng

# xmllintでバリデーション
xmllint --relaxng tei_all.rng sample_tei.xml
sample_tei.xml validates

TEI公式のRelaxNGスキーマ(tei_all.rng)で バリデーションに通る ことを確認しました。

!

OpenITI独自のカスタムスキーマ(tei_openiti.rng)でも検証を試みましたが、434KBと大きいスキーマのコンパイルに非常に時間がかかり、ローカル環境では完了しませんでした。tei_alltei_openiti のスーパーセットであるため、tei_all で通れば基本的な適合性は確認できます。

まとめ

  • oitei を使えば、OpenITI mARkdown → TEI XML の変換がPython数行で可能
  • XMLタグの手書きが不要で、特にRTL言語を扱う際のエディタ上の混乱を回避できる
  • 生成されるXMLはTEI標準スキーマのバリデーションに通る
  • <persName>, <placeName>, <date> 等の固有表現タグが自動付与される

軽量な記法で書いて、必要な時にTEI XMLに変換する。このワークフローは、特にイスラーム圏の歴史テキストを扱う研究者にとって有用なアプローチです。

参考リンク