MSワードで背景色をつけてそれに対応するTEIタグに変換するスクリプト

タグの操作に慣れるのが大変なので、MSワードでタグ付け作業をしたい、というニーズが最近は見られるようになってきました。そこで…

MSワードで背景色をつけて、それに対応するTEIタグに変換するスクリプトを作ってみました。

MSワードは、実はXMLで構造化されたデータなので、TEIへの変換は原理的にはかなり簡単です(ただしレイアウトが複雑になると難易度が増します)。

Python の場合、この変換を簡単にしてくれる便利なモジュールがありますので、まずは以下のコマンドにて、それをインストールしておきます。

$ python -m pip install python-docx

Google Geminiなどに聞けば色々教えてくれるので、細かいことはそちらに聞いていただくとよいので、ここでは概要だけ。

MSワードの docx ファイルを 7zなどのZIPファイル展開ツールで無理矢理ZIP展開すると、ファイル名と同じ名前のフォルダができます。そのなかの「word」というフォルダの中の document.xml というファイルが、本文のファイルです。これをなんか便利なツールで(Googleとかでもよい)開くとXMLタグのついたテキストが表示されます。

ここで、たとえば、イベント名のところにシアン色の背景色をつけた場合は、以下のようになります。

「<w:highlight w:val="cyan"/>」という風になっていますね。この「w:val=」の値である「cyan」が、つけた背景色の名称です。これをキーにして、対応するタグ名を設定することになります。

以下のプログラムはかなり単純な構造のファイルの場合に有効なものですが、この「tag_hl_dict=」という辞書の値に、背景色とそれに対応する変換したいタグの名前を入れていくと、あとは…(以下に続く)

from docx import Document  
import sys  
doc = Document(sys.argv[1])  
all_text = '<body>'
ns = {'w': 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'}

#以下のところに背景色名と対応するタグ名を記入していくとそれに対応するタグが追記される
tag_hl_dict={'yellow':'placeName','green':'orgName','cyan':'eventName' }

for p in doc.paragraphs:
    all_text += '<p>'
    for run in p.runs:
        
        rpr = run._element.xpath("w:rPr/w:highlight")
        
        btext = run._element.xpath("w:t")[0].text
        
        if rpr:
            atval = rpr[0].get('{http://schemas.openxmlformats.org/wordprocessingml/2006/main}val')
            if atval != '':
                all_text += '<'+tag_hl_dict[atval]+'>'+btext+'</'+tag_hl_dict[atval]+'>'
            else:
                all_text += btext
        else:
            all_text += btext        
    all_text += '</p>'
all_text += '</body>'
print (all_text)

(上から続く)以下のようなコマンドで変換できます。簡単ですね!

$ python [このスクリプトのファイル名] [変換したいワードのファイル名]

ちなみに、上記の例では、placeName, orgName, eventNameのタグを、それぞれの背景色に対して付与している例です。ワードの文書は以下のような感じに書いていて、

そこから、以下のようなXMLが出力されます。

ごく簡単なものですが、これで概ね必要事項は提供できていると思います。

ついでに書いておきますと、ルビを処理したいときは、またちょっと異なるので、以下のものを参考にしてください。以下のものは、ワードのルビ機能を使って正規化テキストを書いている場合に、それを変換するものです。ルビを単にルビに変換したいだけという場合は、choice, reg, origのタグを、それぞれruby, rb, rtに修正すれば大丈夫です。

from docx import Document  
import sys  
doc = Document(sys.argv[1])  

all_text = '<body>'

for p in doc.paragraphs:
    all_text += '<p>'
    for run in p.runs:
        all_text += run.text
        ruby = run._r.xpath("w:ruby")
        # runに振り仮名が存在するか調べる
        if ruby:
            r = run._r.xpath("w:ruby/w:rt/w:r/w:t")[0].text
            t = run._r.xpath("w:ruby/w:rubyBase/w:r/w:t")[0].text
            all_text += '<choice><reg>'+t+'</reg><orig>'+r+'</orig></choice>'
    all_text += '</p>'
all_text += '</body>'
print (all_text)

このスクリプトと上のスクリプトの合わせ技をすれば、両方できるはずですが、「ルビ付きの人名」のようなものだと微妙にややこしいことになるかもしれないですね。そのあたりはまたいずれ…