!

人手で検証を行った後、AIが記事を執筆しました。

はじめに

TEI(Text Encoding Initiative)XMLを編集する際、要素や属性の構造検証だけでなく、より複雑なビジネスルールの検証が必要になることがあります。本記事では、RELAX NG(RNG)とSchematronを組み合わせて、構造検証と内容検証の両方を実現する方法を、実際のプロジェクトで直面した課題を例に解説します。

解決したい課題

日本の古典文学テキストをTEI XMLで校訂する際、以下のような要求がありました:

  1. ID参照の動的検証 : corresp属性で参照するIDが、実際に文書内のwitness要素に存在することを検証したい
  2. Oxygen XML Editorでの補完機能 : 編集時にIDの候補を自動表示したい
  3. 複数ID参照のサポート : スペース区切りで複数のIDを指定可能にしたい
  4. 特定要素のみ参照を許可 : witness要素のIDのみを参照可能とし、person要素のIDが含まれる場合はエラーにしたい

なぜRNG + Schematronなのか?

RELAX NGの得意分野

  • 要素・属性の構造定義
  • データ型の指定
  • 基本的な内容モデルの定義

Schematronの得意分野

  • XPathベースの複雑な検証ルール
  • 文書内の相互参照チェック
  • カスタムエラーメッセージの提供

この2つを組み合わせることで、構造と内容の両面から厳密な検証が可能になります。

実装例

1. 基本的なRNGスキーマ構造

<<?g/xr<<<<<gma!s!s/!rlm-c-t<s-am-h-art-mva:reamerSntfrRarcs>tNrsxxxdnhn>G>immmasepSaolllt=mrcmnnnna"aehe=sssthtfe="=::ytrim"1"asptoxaT.h=cepn=tE0t"hL:"rI"th=i/to"pt"b/en/e:thrwi>n/ptaw"c:trwr/py.ude/:=trilr/"einae/hi=gxlpt-"=nautch"gxrp.tU.nl:tTog.rpFr./g:-gcw//8rlwn/"ngcwsw?s../w>now1wssr3..t/g.0trco"eudr>icmsg-tpd/cual2.rt/0oeis0r/bc1g1ih//.leXn0imMs"taL/ytS1/rc.aoh0nne"n"m/oa>t-adtaitoantsy/p1e.s0""

2. ID定義とanyURI型の活用

Oxygen XML Editorで自動補完を実現するために、anyURI型を使用します:

<<<<!d/!d/-e<d-e<d-fe/e-fe/eilefil<<efneolinea/tliemn<enemt<<aeeneeenmeeta/l/txmennOl<<eee>nnr:#Oailtte>atrea/tlOnatidx:soir/nmMmt<aeertmboydtn<osi>tenoetdtxmM>enucgo>edntb>=arnratteo=atuIecOae>u"metitr/nr"memDnurtOtle>bai>teleeRmMarei=nub>>e=nnEeoM>s"attum"atF#nrtotlmeyt"lmateyrWiepe>eeta>peis=ne>m=ite>tt"a=""oxi="Wwm">cnmo">iieIo>lnatt=Dr:>n"n""riy>ex/edUsm>sRslpI":"">i>/d>">

ポイント :

  • data type="ID"で一意性を保証
  • data type="anyURI"#付きの内部参照を許可
  • list要素でスペース区切りの複数値を許可

3. Schematronによる高度な検証

<s/c<<shss/c:cc<<<<<<<shphhsss!s/!s/c:a::ccc-ccs-cc"shpttrhhh-hoc-ho/c:atiu::::rh:rs>hrtetllllwar:prrt:utrleeeeiseaeeerfr'rlenettttsswsrpspioe,eer>cnepissopenrtp>niWonnnerteorrgu'o>dinaaastnrnts-$rr=ttmmmsetojtnt"neeeets>Itnoo>wex===esDeikiteist"""ssInefhlts=llctwItpD(nesn"iio=iD=e:(neeItssr"t:"rissDettres)nss)s<nt$siWPeva"e#oa"osat)-:iesetsss<mtssnc$ro,rltrpritursseiturhctkeeIsTysabocsabo:osefmdoofrslh$frslIvr-ne<[snk$itteI:titteDarwr/@"Ietesr=Dvoesr=leiescdnos-i"aks-i"ustncovsskwnelewneephchra""e(igrun(igr-T(e:rlnt(ret(roo$steuvvh$o-ih$ofkt"iseaai(tron(treo>tp=lln$o"f$o"snkl]"uutk>$tk>esee"/ee$oescoeln>>/==ckneokne,t""oe,lre,ce/trnernt'i/or,2ce,2=#:tke)ts)"'lees'=p')iinp#="T#=s:iT'so'atlzo)$tk)$nWieklreldis(eaiinaittnnnsnsnss/PosdtgdtuterW-Pbermijesisatort:olIisrwnidnoii/zs(nntte$Igne-ld(eisis$s:pstspato/ecWk@reiexs(tnmo@I,lncd:/os2i@r,)dxr"me'=/ls,>:p$i)#ld,'i")s/"t>\/Ps>e+r's)o"n/I>ds)

ポイント :

  • sch:letで変数を定義し、XPathで動的に値を取得
  • tokenize()で複数ID参照をパース
  • sch:assertで条件を満たさない場合にエラー
  • sch:reportで条件を満たす場合にエラー
  • role="error"でエラーレベルを指定(warning、info も可能)

4. 実際の使用例

<<<<!??T/-xxET-mmIElsls<<IX-c-cxt/t/>MmhmhmetetLoeoeliexedmdmnH<<it<xeaeasel/l/H>b/tltlt=ailileob>yy"dsisiado使hphphet<<st<sdy<<dreretrWwwtPp/te>a/a/yenent>iiiWeepPrpapa>fsfsptttirree>pppp====:>nntss<rr><<<p><<<p""""/ee>oopss!lr>!lr>shsh/ssnneoo-ed-edctctwss>rnn-mg-mghthtwxs>>>epepwxxmNcccm:m:.mmlaoooaatll:mrrr././e::ierrrrrrpiiid>eee<nenu-dd=wssps/glgrc=="ippepr"a"l.""aAt==r=dx.oaibBn""s"gtntoraicCe##o#>ygycgai"<saanap.pl/"">/saaaeoecn>>paaa=r=.se""g"o/r#>#a/ar1AIsiapnpg.<<Nibpsp/0//aicl/ld"wwm""isis>iie><>ctcdtt>/aralnnrtut/ee<d<icisss/g/otocssl>lnunh>>ee/r/emmxexm>>m/mal1lt"."r0o"n?">?>

実装時の注意点

1. XPath 2.0の構文

Schematron内のXPath式では、for式の構文に注意が必要です:

<l<l!e!e-tfr-t-oe-$rtlr$iueein$rttnvtnuvao$ralkinliedidnid:f:i=:=n(=s$($uiflrcbdoeeosrttrt=urr$$rei$tinsnvodpgakiT(le:fo$in=ktd(eoIis$nkdnuisesbdn)$s,ct=tor2hri$)ernvnegas(lp$iTtdooIekkdleessnn)es,t$2ht)eonkenelse$token

2. IDREF vs anyURI

  • IDREF型 : #を含めることができず、Oxygenでの補完が制限される
  • anyURI型 : #付きの値を許可し、Oxygenが自動的にID補完を提供

3. Schematronのrole属性

  • role="error": 赤色のエラーマーカー
  • role="warning": 黄色の警告マーカー
  • role="info": 青色の情報マーカー

応用例

複雑な相互参照の検証

<s/c<<<<sh!s/!s/c:-c<s-c<<shp-hs/c-hss/c:a:cash:ccrshptarhpc:rrhhdc:atpu:phrdu::ghrtepla:uglla:utresaleesalenssetsserces>cecs>nioreconroe>dntronatrr=t1trtmrt"let>reete>cexeex=esrmtslst"spo=tep=lts"=m"e=lst"ltm"e-1eceeCnmriomiooe:u:rtfanrr(eptde@rp(gsce"t[pon>e@"rcicre:oveslras"erlp>meu)se=p==]"$".l1>.e"/m>tCeoir:rleesmp/)@"c>orresp"/>

条件付き必須属性

<s/c<shs/c:c<<shph!s/c:a:-cwshptr-hhc:atu:ehrtelwan:utrehsalenessercnes>niorYe>dntYr=tYt"etY>cxe-otsMn=tMd"=-itI"DteSmDiiOao:tndcaahlte-esa[(t@@twwrhhieebnnu],t"e>s"\>d{4}-\d{2}-\d{2}$')">

まとめ

RELAX NGとSchematronを組み合わせることで:

  1. 構造検証と内容検証の分離 : それぞれの得意分野を活かした設計が可能
  2. 動的な検証ルール : 文書の内容に基づいた柔軟な検証
  3. エディタ支援 : Oxygen XML Editorなどでの高度な編集支援
  4. わかりやすいエラーメッセージ : 日本語でのカスタムメッセージ

特にTEI XMLのような複雑な構造を持つ文書の編集において、この組み合わせは非常に強力なツールとなります。

参考資料


この記事で紹介したスキーマの完全なコードは、実際のプロジェクトで使用されているものです。同様の課題を抱えている方の参考になれば幸いです。