XMLの変換
はじめに
Wolfram言語はパターンマッチング機能がパワフルで,組込みの構造的な操作関数も数多く含んでいるので,記号式の処理には比類なく秀でている.このチュートリアルではXMLデータの処理にWolfram言語を使う例をいくつかご紹介する.
任意のXMLドキュメントをWolfram言語にインポートするとき,このドキュメントは自動的に記号的なXML式に変換される.記号的なXMLはXMLドキュメントをWolfram言語のシンタックスで表すために使われる形式である.XMLドキュメントは記号的なXMLに変換される際,その構造を保ったままWolfram言語式に変換される.XMLデータを記号的なXMLに変換することによって,Wolfram言語の組込み関数を使って直接記号的なXMLが操作できるようになる.
XML木構造の可視化
多くのXMLツールは,XMLドキュメントを折りたためる木構造で表示する.この木構造では,ノードはドキュメントの要素に相当する.ここではWolfram言語ノートブック中でセルのグループ化を使い,どのようにして同様の視覚化を行うかを示す.
このために記号的なXML式を再帰的に見て行き,各XMLElementオブジェクトに対して,そのXMLElementオブジェクトの各属性と子に対するセルを含むCellGroupData式を作成する.ネストした各CellGroupData式は,その前のものに対してインデントされる.ここではまずXMLElementオブジェクトを処理する関数から始める.
ここではインデントに整数 m を使っていることに注意されたい.XMLNoteをXMLElementオブジェクトの子にマップするとき,子要素のインデントを増やすために,より大きな値の m を渡す.
CellGroupData式はセルのリストを含んでいる.定義では,実際にセルを作ったのはXMLElementの x に対してのみである.しかし,それからXMLNoteを属性のリストにマップした.これはリストを返すので,結果に対してApply[Sequence]を使って,リストをCellGroupData式のセルのリストに結合しなければならない.それからXMLElementの子についても同様のことを行う.
しかし,属性に対して使えるXMLNoteをまだ定義していない.XMLElementオブジェクトの属性は記号的なXMLに規則として保存される.多くの場合,この規則はキーと値の2つの文字列を含んでいる.しかし,名前空間が関係している場合,規則の最初の要素は名前空間とキーの2つの文字列を含むリストであるかもしれない.そこで属性を扱うために2つの定義が必要になる.
簡単な記号的なXML式を処理するためには定義がもう1つ必要である.XMLドキュメントのテキストノードは記号的なXMLでは単純にStringオブジェクトとして保管される.従って,Stringオブジェクトを扱う定義が必要なのである.
"IncludeEmbeddedObjects"オプションのデフォルトの値はNoneであるので,コメント,処理命令,あるいはXMLObjectに保管される他のどのようなものにも変更を加えなかった.これらのものに対する定義を追加することは難しいことではなく,記号的なXMLを処理する上でよい練習となるであろう.
XMLデータの操作
XMLアプリケーションはドキュメントレイアウト以外のことにも使われる.XMLは構造化されたデータを保管するのにも優れた形式である.多くの商用データベースの製造元は,製品にXMLのサポートを組み込むようになった.これにより,中間形式としてXMLを使ってデータベースを操作できるようになった.
Wolfram言語には記号的パターンマッチング機能があるため,XMLドキュメントから情報を抽出したり操作したりするのに理想的である.例として,XMLファイルに収められた野球のメジャーリーグ選手のデータを使ってみる.
記号的なXMLは任意のXMLデータを表すための汎用形式である.時には記号的なXMLを異なるタイプのWolfram言語式に変換した方が使いやすいこともあるだろう.このような変換は,パターンマッチングを使って行うと簡単である.
プレーヤーに関するすべての情報は,Pitcherという頭部を持つWolfram言語規則のリストに保管されている.
データを別の式のシンタックスに変換することに加え,データを変更し,式全体を記号的なXMLのまま残しておくこともできる.このようにするとデータが変更できるが,やはり他のアプリケーションで使えるようにデータをXMLファイルにエキスポートする.
XSLTとWolfram言語の比較
あるXML形式のドキュメントを他の形式のものに変換する必要があることが多々ある.この目的で使われる一般的な技術のひとつにXSLT変換がある.Wolfram言語にはパワフルなパターンマッチング・変換機能があり,もとのドキュメントをインポートし,記号的なXML式を操作すると,同様の変換が簡単に行える.このセクションでは基本的なXSLT変換と,それと同様のWolfram言語を使った変換の例を見ていく.
簡単なテンプレート
この例では,XML方言がcodeタグを使ってプログラムコードを囲む.通常これは等幅フォントで表示される.このようなドキュメントをXHTMLに変換する場合,恐らくコードに対してpreタグを使うのが一般的であろう.
<xsl:template match="code"> <pre class="code"> <xsl:value-of select="."/> </pre> </xsl:template>
属性の値を挿入する
新しい項目の定義を示すtermdef を使用するXMLアプリケーションを考えてみる.ここで,ドキュメントの目的の場所に直接リンクされるように,定義にa要素でアンカータグを付加する.termdef 要素内にどのような文字列形式が存在しても扱うことのできるテンプレートがあると仮定すると,以下のXSLTを使うことができる.
<xsl:template match="termdef"> <span class="termdef"> <a name="{@id}">[Definition:] </a> <xsl:apply-templates/> </span> </xsl:template>
結果として得られるXHTML中のname属性がもとのtermdef要素のid属性の値を持っていることに注意されたい.
記述を使用する
より複雑な例として,XPath記述を使うものを考えてみる.note要素がexampleに設定されているrole属性を持っている場合,またはeg子要素を含んでいる場合のみnote属性をマッチさせたいとする.以下のXSLTテンプレートが何を行っているのかを見てみる.
<xsl:template match="note[@role='example' or child::eg]"> <div class="exampleOuter"> <div class="exampleHeader">Example</div> <xsl:if test="*[1][self::p]"> <div class="exampleWrapper"> <xsl:apply-templates select="*[1]"/> </div> </xsl:if> <div class="exampleInner"> <xsl:apply-templates select="eg"/> </div> <xsl:if test="*[position()>1 and self::p]"> <div class="exampleWrapper"> <xsl:apply-templates select="*[position>1 and self::p]"/> </div> </xsl:if> </div> </xsl:template>
初めのxsl:if要素は最初の子要素がp要素であるかどうかを確認する.p要素である場合はその子要素に対してxsl:apply-templatesが呼び出される.これはCasesの結果に対してMapを呼び出すのに似ている.2つ目のxsl:if要素では1つ目の子要素の先にp要素が存在するかどうかを確認する.存在する場合は,それらについてxsl:apply-templatesが呼び出される.これに対応するWolfram言語のコードを以下に示す.
上の階層を見る
先祖や兄弟の要素を選ぶには,XMLドキュメントは単に文字のストリームであり,それが文法規則に従っているだけであるということを理解しなければならない.XMLドキュメントを操作するツールは何らかのモデルに従ってXMLを扱う.XSLT(およびそのパス選択言語,XPath)の場合は,このモデルは木構造である.Wolfram言語はリストベースの言語なので,XMLをネストした式のリストとして扱う.
この2つのモデルは似ているが,重要な違いがある.最大の違いは,ネストしたリストでは,含んでいるリストのコンセプトは本質的には持たないということである.理論的には,先祖等の軸タイプでできる変換はどれもそれがなくても行える.しかし,XMLドキュメントの上方を見ることもしばしば有用である.
bibref要素にマッチするテンプレートが必要であり,それを対応するbibl要素内のテキストと置き換えるとする.XSLTでは以下のようなテンプレートになる.
<xsl:template match="bibref"> <xsl:param name="ref"> <xsl:value-of select="@ref"/> </xsl:param> <xsl:value-of select="/bibliography/bibl[@id = $ref][1]"/> </xsl:template>
ノートブックのHTMLへの変換
「ファイル」 ▶ 「別名で保存」ダイアログのファイルの種類サブメニューにリストされている形式ではなく,ある特定のXML形式にノートブックをエキスポートする必要があるとする.ひとつの方法として,NotebookMLにエキスポートした後,外部のツール(XSLT規則等)を使ってXMLの希望の形式に変換するということが挙げられる.しかし,Wolfram言語内で操作を行い,ノートブック式を直接記号的なXMLに変換し,それを保存するという方法も簡単であることがある.Wolfram言語パターンとプログラミングの基礎的なコマンドをご存知の方ならこれができるであろう.Wolfram言語式は基本的には木構造で,その手法はXSLTによく似ているので,XSLTの知識を持つユーザは前に同じようなものを見たことがあると感じるかもしれない.
例として「ファイル」 ▶ 「別名で保存」 ▶ 「Web Page (*.html)」機能の簡単なものを作り直してみる.
ここでは,もとのノートブック式を最初から最後まで処理するために,再帰的な関数transformを定義する.これはXSLTのテンプレートと似ている.
transformは再帰的に適用されるため,定義では Sequence[]が使ってある.「null」の結果に最適なのは,シンタックスに従ったまま引数のリストの中央に入ることができるものである.
- 引数のパターンは,すべての変数を受け入れられるように強固なものでなければならない(ノートブックオプションがこの変換で削除されてしまっても,そのオプションを考慮に入れるためにBlankNullSequence (___)が含まれる).
- 第3引数は常にListである.これは忘れがちな点である.
- 繰返しはReplaceRepeatedで暗示的に行われるので,後者の実装の方がスポット的には簡単である.特にTextセルの操作について比較すると,TextDataの規則はCellの規則と切り離すことができるので,後者の方が簡単ですある.繰返し関数に対しても同様のことが行えるが,contentsが取るさまざまな形式(_List対_String等)のための追加パターンにコストがかかる.ReplaceRepeatedはすべてのサブ式に対して作用することで,この必要性を未然に回避する.
記号的なXMLのシンタックスの検証
XML`SymbolicXMLErrorsを使うと,記号的なXML式のエラーを見付けることができる.この関数は,PartやExtract等の関数を使って記号的なXML式の問題の部分にアクセスするときに使える場所指定を返す.