AIを使ってXMLを「復権」させる(後編の1)
前回の記事では、XMLでデータベースを作りChatGPTと組み合わせると、いろいろ面白いことが出来そうだと述べました。
今一度、「登場人物データベース」を例題として取り上げます。その構築にもChatGPTを利用できるという話をしたいと思います。
XMLデータベースの復習
登場人物XMLデータベースは、こんな見た目をしていました。
<?xml
version="1.0" encoding="UTF-8"?>
<db xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="chars.xsd">
<chars>
<item id="momotaro">
<name>桃太郎</name>
<gender>男</gender>
<desc>
桃から生まれた強い子。 鬼ヶ島に鬼を退治に行く。
</desc>
</item>
<item id="inu">
<name>犬</name>
<gender>男</gender>
<desc>
桃太郎に黍団子を貰って子分になる。一緒に鬼を退治に行く。
</desc>
</item>
<item id="saru">
<name>猿</name>
<gender>男</gender>
<desc>
桃太郎に黍団子を貰って子分になる。一緒に鬼を退治に行く。
</desc>
</item>
<item id="kiji">
<name>雉</name>
<gender>男</gender>
<desc>
桃太郎に黍団子を貰って子分になる。一緒に鬼を退治に行く。
</desc>
</item>
</chars>
<rels>
<item id="momotaro_inu">
<char1>momotaro</char1>
<char2>inu</char2>
<type>
家来
</type>
</item>
<item id="momotaro_saru">
<char1>momotaro</char1>
<char2>saru</char2>
<type>
家来
</type>
</item>
<item id="momotaro_kiji">
<char1>momotaro</char1>
<char2>kiji</char2>
<type>
家来
</type>
</item>
</rels>
</db>
とりあえず、このXMLデータベースを`chars.xml`と名付けてセーブしておきましょう。
前回は、このXMLをChatGPTにアップロードして活用できるという可能性を見ました。今回は、その前段階の話です。
XMLデータの整備
記述ルールを整備する:ChatGPTが役に立つ!
XMLデータの中にどんなタグを置き、そこにどんな値を置くのか。どんな値が許され、どんな値が許されないのか。
こういった一連のルールを策定し、かつ、そのルールにそったXMLデータが作れているかを随時簡単にチェックすることができます。そのために使える仕組みの一つがXML Schemaです。
今回、chars.xml用のルールとして以下のようなものを考えてみました。
次の要求を満たすXML Schemaを作成し、完全な形式のXMLとして出力してください。
"""
- ルートタグとしてdbを使用。
- ルートタグの直下には、chars, relsのいずれかのタグを置くことができる。いずれのタグも0回または1回出現するものとし、出現の順序は任意とする。
- chars, relsタグの直下にはitemタグが並ぶ。
- itemタグは必ずid属性を持つ。id属性の値は半角小文字のみからなる文字列とする。id属性の値は、このXMLデータ全体の中でユニークでなければならない。
- 全ての<chars><item>タグの下に必ず一つ以上のnameタグが存在しなければならない。
- itemタグの下の子タグの出現順位は任意とする。
- descタグをitemタグの下に置くことができる。 descタグ内にはフリーテキストによる当該itemの説明を書く。
- 全てのタグには、in属性を付加できる。作品ごとに異なる設定が存在する場合、タグの中にin属性を付加することで、当該要素に書かれた情報がin属性で指定された作品のみに通用することを示す。
- <chars><item>直下には、共通仕様で定義したタグの他に次の子タグを置くことができる。
- name -- 本名
- alias -- 別名
- birthday -- 誕生年月日
- deathday -- 死亡年月日
- occupation -- 職業
- gender -- 性別
- age -- 年齢
- rels要素には、キャラクタ間の関係性を記述する。
- <rels><item>要素の直下にはchar1,char2,typeの三つの子タグを置く。一つの<rels><item>要素は、char1から見てchar2がtypeであることを意味している。
"""
ここで、ChatGPT先生に登場いただきます。上記をプロンプトとしてそのまま提示します。
すると次のようなXMLデータが出力されます。
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="db">
<xs:complexType>
<xs:choice maxOccurs="unbounded">
<xs:element ref="chars" minOccurs="0" maxOccurs="1"/>
<xs:element ref="rels" minOccurs="0" maxOccurs="1"/>
</xs:choice>
<xs:attribute name="in" type="xs:string" use="optional"/>
</xs:complexType>
<xs:unique name="uniqueID">
<xs:selector xpath=".//item"/>
<xs:field xpath="@id"/>
</xs:unique>
</xs:element>
<xs:element name="chars">
<xs:complexType>
<xs:sequence>
<xs:element ref="item" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="in" type="xs:string" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="rels">
<xs:complexType>
<xs:sequence>
<xs:element ref="item" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="in" type="xs:string" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="item">
<xs:complexType>
<xs:choice maxOccurs="unbounded">
<xs:element name="name" type="xs:string"/>
<xs:element name="alias" type="xs:string"/>
<xs:element name="birthday" type="xs:date"/>
<xs:element name="deathday" type="xs:date"/>
<xs:element name="occupation" type="xs:string"/>
<xs:element name="gender" type="xs:string"/>
<xs:element name="age" type="xs:int"/>
<xs:element name="desc" type="xs:string"/>
<xs:element name="char1" type="xs:string"/>
<xs:element name="char2" type="xs:string"/>
<xs:element name="type" type="xs:string"/>
</xs:choice>
<xs:attribute name="id" type="xs:string" use="required"/>
<xs:attribute name="in" type="xs:string" use="optional"/>
</xs:complexType>
</xs:element>
</xs:schema>
うわ、複雑。これをエディタに手入力するとしたらかなり面倒くさい作業になりそうです。しかし、ChatGPTを使えば一発です。細かい文法がうろ覚えでも恐れる必要は無し。ChatGPTが全部よろしく面倒を見てくれるので(実際には問題が発生する可能性がゼロではないのですが、そのへんは別記事で)。
このXMLテキストをファイルにセーブします。ファイル名は何でもいいですが、末尾には`.xsd`を付けておくことを推奨します。ここではdb.xsdとしておきますか。
schemaに記述したルールに沿って、データをチェックする
xmllintというツールを使えるようにしておき、コマンドラインから次のように打ち込みます(この辺のセットアップやオペレーションの詳細については後日別記事にしようと思います)。schemaであるdb.xsdに基づいてchars.xmlの内容が適正か確認せよという命令です。
xmllint --schema db.xsd --noout chars.xml
何事もなければ、
chars.xml validates
のようなシンプルなメッセージのみが返ってくるでしょう。
ではここで、故意に不適切な加筆をしてみましょう。IDを不適切にダブらせた要素と、不適切に欠落させた要素。これらを追加してみます。
一時ファイルとして別名保存したXMLファイルを対象に、同じようにxmllintを実行すると、先ほどとは違い、下のようなメッセージが現れます。
char_test.xml:35: element item: Schemas validity error : Element 'item': Duplicate key-sequence ['kiji'] in unique identity-constraint 'uniqueID'.
char_test.xml:43: element item: Schemas validity error : Element 'item': The attribute 'id' is required but missing.
char_test.xml fails to validate
「35行目:'kiji'というIDが重複。43行目:id属性が必要なのに欠けている」
ルールに沿って、不適切なポイントがちゃんと指摘されているのがわかるでしょうか?
もはやデータ構築は辛くない
このように、XMLにはデータの妥当性検証のための仕組みが用意されており、そのお膳立てにはChatGPTが使えるのです。
また、詳しく書きませんでしたが、XMLデータ入力に使えるエディタのVScodeには、強力な入力補完機能があり、入力時のミス削減・労力削減に大いに力を発揮してくれます。
終わりに
今回は、データ構築にChatGPTが使えることを見ました。これによって、XMLの構造の複雑さ・厳密さ、それによるデータ構築・維持の面倒くささが相当に軽減できるということです。
実は、XMLの応用においてもChatGPTによって利便性を高める余地があるという話をしたかったのです。
ですが、既に長い記事になってしまいました。今回でXML編は区切りをつけるつもりでしたが、もう一回だけ延長したいと思います。また、xmllintのインストールや操作、その前の環境整備についても別途紹介する記事を作る予定です。