Genericode は、OASIS (Organization for the Advancement of Structured Information Standards) 仕様 UBL (Universal Business Language) 技術委員会から生まれました (「参考文献」を参照)。当初、UBL が従っていたのは、UN/CEFACT (United Nations Centre for Trade Facilitation and Electronic Business) コア構成要素技術仕様 (「参考文献」にリンクを記載) です。この仕様では、列挙型を使用して通貨コードや国名コードなどのコード・リストを W3C の Schema に直接埋め込んでいました。
UBL コミュニティーはまもなくして、コード・リストが頻繁に変更されることに気付きました。リストを直接スキーマに直接埋め込むという方法は、検証には楽でしたが、リスト内のコードが変更された場合にはスキーマを更新しなければなりません。取引相手が複数いるとなると、更新したスキーマを扱うのはロジスティクスの悪夢となり得ます。さらに、スキーマを再コンパイルして、更新後のスキーマを基にデータベースを再初期化しなければならない製品も数多くあります。
UBL 技術委員会は、コードが変更されるたびにスキーマを更新しなければならないという問題を解消するための抽象化層として、Genericode を開発しました (詳しくは「参考文献」のリンクを参照)。また、Schematron などの他の検証手法を、コードを検証する検証層として使用することができます。Genericode は UBL よりも幅広く支持される結果となったため、OASIS は Genericode 仕様を管理する新たな技術委員会を発足することにしました。
この記事では、Microsoft Office Excel 2007 スプレッドシートを使ってコード・リストを作成する方法を説明し、さらに XSLT を使用してコード・リストを Excel スプレッドシートの形式から Genericode に変換する方法を説明します。
記事では Genericode への変換を具体的に取り上げますが、その概念は、他のタイプの Excel 文書や XML 語彙にも一般論として当てはめることができます。例えば、私は Microsoft Office Excel 2003 への変換、またはこの形式からの変換を数多く行ってきましたが、そのなかで、この変換プロセスがかなり直接的なものであることに気付きました。Office Excel 2003 形式から XML 形式に変換する場合は、スプレッドシートを Office Excel 2003 XML に保存するといった具合です。私が作成した変換の 1 つは、W3C のスキーマからスプレッドシートへの変換で、スキーマ分析スプレッドシートが作成されるものです。Excel 形式にすることで、技術系ではない人々でもスキーマ・コンポーネント間の関係、そしてスキーマ・コンポーネントそれぞれの定義を容易に理解できるようになります。
私が作成したもう 1 つの使える変換は、Office Excel 2003 XML から Genericode への変換で、これは本番環境でも適切に動作します。コード・リストには空のセルがある場合が多いですが、Office Excel 2003 XML で空白になっているセルは、この変換では XML には出力されませんでした。また、行を分析してどのセルが省略されているかを自動的に判断する簡単な方法もありませんでした。この問題は、Office Excel 2003 と Office Excel 2007 の両方に当てはまります。ただし、Office Excel 2007 には、セルが空白になる場合を論理的に解明する機能が用意されています。
この記事ではサンプルとして、図 1 に示す単純な構造を使用します。これは、Excel コード・リストです。
図 1. サンプル Excel コード・リスト
OASIS Genericode と Office Excel 2007 の構造
変換プロジェクトを開始する前には、必ず最初の構造と最終的な構造を理解しておかなければなりません。Genericode は複雑になることもありますが、コード・リスト全体の 98 パーセントは比較的理解しやすいものです。単純なコード・リストは、以下の 3 つのセクションに分けられます。
- ID
- 列の仕様
- コード・リストのデータ
図 2 に、Genericode の XML スキーマを図解します。CodeList 文書 (型: gc:CodeListDocument) には、その文書を記述する複数の属性があります。gc:DocumentHeader に含まれるのは、Annotation (型: gc:Annotation) と Identification (型: gc:Identification) です。gc:ColumnSetChoice には ColumnSet (型: gc:ColumnSet) と ColumnSetRef (型: gc:ColumnSetRef) が含まれ、gc:OuterCodeListChoice には gc:SimpleCodeListSequence と SimpleCodeList (型: gc:SimpleCodeList) が含まれます。
図 2. Genericode の構造
一方、Office Excel 2007 XML は Genericode コードほどには単純ではありません。実のところ、その構造はかなり風変わりです。XLSX ファイルは実際には ZIP ファイルであり、複数のファイルが含まれます。
- ルートには以下のディレクトリーがあります。
- _rels
- docProps
- xl
- _rels
- printerSettings
- theme
- worksheets
それぞれのディレクトリーごとに、数多くの XML ファイルが保管されています。変換の際には、このすべてのファイルやそれぞれの目的を考える必要はありません。これらのファイルのうちのいくつかは、Excel が Excel アプリケーションを制御するために内部で使用するファイルだからです。この記事での変換に関与するファイルとしては、以下のものがあります。
- /docProps/app.xml: 組織の情報が含まれます。
- /docProps/core.xml: 時刻や作成者などのメタデータが含まれます。
- /xl/worksheets/sheet1.xml: データへのマッピングが含まれます。
- /xl/sharedStrings.xml: 実際のデータが含まれます。
これらのファイルにはロジックがありますが、一見しただけでは、そのロジックはわかりません。
sharedStrings.xml ファイルと sheet1.xml ファイルは連携しています。まず、図 1 の Excel コード・リストの sharedStrings.xml ファイルについて見ていきましょう。リスト 1 に、この XML ファイルのファイル構造を記載します。
リスト 1. sharedStrings.xml のファイル構造
<sst>
<si>
<t>My Data 25</t>
</si>
<si>
<t>My Data 10</t>
</si>
...
</sst>
|
興味深いことに、sharedStrings.xml ファイルでのデータの組み込み方には論理的順序があるようには見えません。このファイルは基本的に Excel スプレッドシートのすべてのセルを一様に記述しているだけです。
データの保管場所は、以下のようにセルのデータ型に応じて異なります。
- 文字列データ: sharedStrings.xml ファイルに配置され、このファイル内で検索されます。
- 整数データ: sheet1.xml ファイルに配置されます。
- 式データ: sheet1.xml ファイルに配置されます。
注: 式データをコード・リストに含めるというようなケースはまず考えられません。
sheet1.xml はデータへのマッピングを提供するファイルです。sheet1.xml のファイル構造は図 3 のようになっています (図 3 をテキストで表現したものを見るには、ここをクリックしてください)。
図 3. sheet1.xml の構造
データそのものは <row> 要素に含められます。表 1 に、sheet1.xml ファイルの要素を記載します。
表 1. sheet1.xml の要素および属性
| 要素または属性 | 説明 |
|---|---|
row | Excel スプレッドシートの行の開始 |
@r | 行番号 |
@spans | 行に含まれる列の数。最初の数値が開始列で、2 番目の数値が終了列です。 |
c | セルに関する情報 |
@r | セルの物理的な位置。例えば、B10 は列 B、行 10 の位置となります。 |
@s="1" | セルの実際の値。この属性が指定されている場合、sharedStrings.xml ファイル内を検索する必要はありません。 |
@t | データ型。例えば、s は文字列を表します。@t が指定されている場合は、sharedStrings.xml ファイルで <v> 要素の値が検索されます。 |
v | <si> 要素の番号に 1 を足した数値が含まれます。これは、sharedStrings.xml ファイル内で実際のデータが配置されている位置です。 |
要素に含まれる値は、sharedStrings.xml ファイル内にある <si> 要素の XPath 番号に 1 を加えた値です。t 属性値は s に設定されます。s は、文字列の値を表します。
2 番目と 3 番目のセルには t 属性がありません。t 属性がないということは、データがこのファイルに含まれていることを意味します。計算が行われるフィールドの場合、その先頭文字としてプラス記号 (+) が組み込まれるので、整数と区別することができます。
Office Excel 2007 には複数のファイルがあること、そして変換手法はさまざまな方法で開発できることから、基準とする XML ファイルを選択する必要があります。sheet1.xml には、データへのマッピングが含まれていることから、ここでは sheet1.xml ファイルを基準 XML ファイルとして使うことにしました。データ・ファイル (sharedStrings.xml) は静的なので、このファイルからインテリジェントなナビゲーションを推測するのは難しい話です。前述のとおり、Genericode には 3 つの主要な情報コンテナーがあるので、各コンテナーの変換について見ていきましょう。
検索は、複数のファイルで行わなければなりません。そこで、さまざまなファイルの完全パス名を使用する代わりに、グローバル変数を作成すると、検索が容易になるとともに、コードが読みやすくなります。
以下のパラメーターが、XML ファイルのルート・ディレクトリーを設定します。XProc パイプラインやバッチ・ジョブを使用して複数のコード・リストを変換する場合には、このパラメーターの値をそのプロセスに送信することができます。
<xsl:param name="ExcelRoot">MyCodelist</xsl:param> |
以下に記載する変数を使用して、情報が含まれるファイルの完全パスおよびファイル名を取得します。
<xsl:variable name=”DataFile”> <xsl:value-of select=”$ExcelRoot”/>/xl/sharedStrings.xml</xsl:variable> |
変換の出発点となるのは、<worksheet> テンプレートです。リスト 2 に <worksheet> 要素のテンプレートの一例を記載します。基本的に、この最初のテンプレートは各セクションの変換を呼び出します。最初に変換するファイルは、sheet1.xml です。名前空間接頭辞は「Excel」であり (必要に応じて変更しても構いません)、ルート要素は <worksheet> です。したがって、このテンプレートは Excel:worksheet との突き合わせを行うことに注意してください。
リスト 2. 最初のテンプレート
<xsl:template match="Excel:worksheet">
<CodeList xmlns="http://docs.oasis-open.org/codelist/ns/genericode/1.0/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:era="http://archives.gov/era/schema"
xsi:schemaLocation="http://docs.oasis-open.org/codelist/ns/genericode/1.0/
http://docs.oasis-open.org/codelist/cs-genericode-1.0/xsd/genericode.xsd">
<xsl:call-template name="commentBlock"/>
<xsl:call-template name="identificationBlock"/>
<xsl:call-template name="createColumnSet"/>
<xsl:apply-templates/>
</CodeList>
</xsl:template>
|
Excel 固有の不要なデータを削除するために、デフォルトのテンプレートも作成する必要があります。
<xsl:template match=”*”/> |
この記事では、コード・リストの本体 (<SimpleCodeList>) に専念します。このロジックがあれば、他のセクションを開発するのは簡単だからです。Excel コード・リストのテンプレートに関しては、それぞれの組織に独自の手法があります。
<SimpleCodeList> および <Row> 出力の作成
<sheetData> 要素は、<worksheet> 要素の直接の子です。<SimpleCodeList> 要素は、この <sheetData> 要素から派生され、<Row> 要素は、<row> 要素から派生されます。このとおり、単純明快な仕組みです。リスト 3 に、<SimpleCodeList> 要素と <Row> 要素を作成する XML を記載します。
リスト 3. <SimpleCodeList> および <Row> の作成
<xsl:template match="Excel:sheetData">
<SimpleCodeList>
<xsl:apply-templates/>
</SimpleCodeList>
</xsl:template>
<xsl:template match="Excel:row">
<Row>
<xsl:apply-templates/>
</Row>
</xsl:template>
|
Genericode では、そこに含まれるすべてのエントリーに列参照を使用することを要件としています。列参照情報は、<ColumnSet> 要素内に取り込まれます。<Identification> および <ColumnSet> エントリーは、それぞれの組織がそのコード・リストを Excel 形式で保持するために使用するテンプレートによって異なるため、これらのエントリーの作成方法はここでは説明しません。ただし、<Value> 要素に @ColumnRef 情報を取り込むには、列参照情報が必要です。
各見出しに対応する変数は、手動で設定します。これらの変数を設定するには、おそらくもっと洗練されたやり方があると思いますが、この方法でも上手くいきます。見出しの変数の次は、列の変数を作成します。リスト 4 では、セル A2 の <v> 要素の値を選択しています。番号付けは 0 から始まるため、<v> の値には 1 を加算しなければならないことに注意してください。
リスト 4. 列参照の作成
<xsl:variable name="ColumnALocation">
<xsl:value-of select=
"//Excel:worksheet/Excel:sheetData[1]/Excel:row[2]/Excel:c[1]/Excel:v + 1"
/>
|
この列参照から、セルに含まれる実際の値を取得する必要があります (リスト 5 を参照)。この例では、列の位置がヌルではないことを確認するためのテストを行います。列の位置の値がヌルでなければ、sharedStrings.xml ファイルで検索を行います。このファイルでは、位置の軸 (position()) が sheet1.xml の <v> 要素に含まれる値に相当します。この変数は、後で @ColumnRef 属性を判断するために使用します。
リスト 5. セルに含まれる実際の値の取得
<xsl:variable name="Column-A">
<xsl:choose>
<xsl:when test="$ColumnALocation = ''"/>
<xsl:otherwise>
<xsl:value-of
select="document($DataFile)/Excel:sst/Excel:si[position() =
$ColumnALocation]"
/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
|
図 1 をもう一度見てみると、列 A1 の値は a1 となっていることがわかります。したがって、Genericode による表現は以下のようにしなければなりません。
<Value ColumnRef="ColumnA">
<SimpleValue>a1</SimpleValue>
</Value>
|
<c> 要素の @r 属性に含まれるのはセルの座標です。例えば、A2 とある場合、これは列 A の行 2 を表します。この例では、列の見出しは A2、B2、C2 となっていますが、タイトルと列の見出しがそれぞれどのセルにあるのかを知る必要があります。
そこで、以下の 3 つの変数を設定します。
column: 列番号。例えば、Bは 2 番目の列を表します。この情報は、@rの値に含まれます。dataLoc: データの位置。これは、sharedStrings.xml ファイル内でデータが置かれている位置を示す、XPath + 1 の位置です。cellValue: セルに含まれる実際のデータ。この変数は、sharedStrings.xml ファイルを直接検索して設定します。
変数を設定した後、データの取り込みを開始します。このプロセスの後半では、@ColumnRef 属性に値を取り込みます。これは同じテンプレートで行うこともできますが、ここでは、2 つ目のテンプレートを作成し、そこに column 変数を送信して列の名前を検索することにします (リスト 6 を参照)。
リスト 6. サンプル <c> テンプレート
<xsl:template match="Excel:c">
<xsl:variable name="column"><xsl:value-of select="substring(@r, 1, 1)"/>
</xsl:variable>
<xsl:variable name="dataLoc"><xsl:value-of select="number(Excel:v) + 1"/>
</xsl:variable>
<xsl:variable name="cellValue">
<xsl:value-of
select="document($DataFile)/Excel:sst/Excel:si[position() = $dataLoc]"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="Excel:v">
<Value>
<xsl:attribute name="ColumnRef">
<xsl:call-template name="getColref">
<xsl:with-param name="column"><xsl:value-of select="$column"/>
</xsl:with-param>
</xsl:call-template>
</xsl:attribute>
<SimpleValue><xsl:value-of select="$cellValue"/></SimpleValue>
</Value>
</xsl:when>
<xsl:otherwise/>
</xsl:choose>
</xsl:template>
|
パズルを完成させる最後のピースは、列名の取得です。コード・リストに多数の列があるのではない限り、リスト 7 の方法で十分対処することができます。ほとんどのコード・リストでの列数は、2 列から 5 列といったところです。
リスト 7. 列参照の作成
<xsl:template name="getColref">
<xsl:param name="column"/>
<xsl:choose>
<xsl:when test="$column = 'A'">
<xsl:value-of select="translate($Column-A, ' ', '')"/>
</xsl:when>
<xsl:when test="$column = 'B'">
<xsl:value-of select="translate($Column-B, ' ', '')"/>
</xsl:when>
<xsl:when test="$column = 'C'">
<xsl:value-of select="translate($Column-C, ' ', '')"/>
</xsl:when>
</xsl:template>
|
傾向として、コード・リストの所有者は Microsoft ツールを使い慣れているビジネス・ユーザーである場合がよくあります。そのようなビジネス・ユーザーであれば、お馴染みの Microsoft ツールでコード・リストのデータを更新し、管理することができます。したがって、XSLT を使用して技術要件をビジネス要件に変換することは、極めて意味のあることです。ほとんど手間もかからずに、ビジネス分野のエキスパートが扱うべき内容と技術上の必要性とを切り分けることのできるワークフローは、効率的かつ実際的な技術ソリューションです。
学ぶために
- OASIS Universal Business Language (UBL) TC: UBL 技術委員会の詳細を学んでください。
- UN/CEFACT コア構成要素技術仕様: このガイドで、ebXML 概念の解釈あるいは実装について読んでください。
- Genericode: コード・リストを XML 形式にエンコードするための OASIS 仕様を読んでください。
- XProc: An XML Pipeline Language (W3C 勧告、2010年5月11日): XML 文書で実行される操作を記述するための言語、XProc について詳しく学んでください。
- developerWorks の XML エリア: XML 分野でのスキルを磨くための資料を入手してください。
- My developerWorks: developerWorks のエクスペリエンスを自分流にカスタマイズしてください。
- IBM XML 認定: XML や関連技術の IBM 認定技術者になる方法について調べてください。
- XML technical library: 広範な技術に関する記事とヒント、チュートリアル、標準、そして IBM Redbooks については、developerWorks XML ゾーンを参照してください。また、XML に関するヒントを読んでください。
- developerWorks の Technical events and webcasts: これらのセッションで最新情報を入手してください。
- developerWorks on Twitter: 今すぐ登録して developerWorks のツイートをフォローしてください。
- developerWorks podcasts: ソフトウェア開発者向けの興味深いインタビューとディスカッションを聞いてください。
- developerWorks オンデマンド・デモ: 初心者向けの製品のインストールおよびセットアップから熟練開発者向けの高度な機能に至るまで、さまざまに揃ったデモを見てください。
製品や技術を入手するために
- IBM 製品の評価版: DB2®、Lotus®、Rational®、Tivoli®、および WebSphere® のアプリケーション開発ツールとミドルウェア製品を体験するには、評価版をダウンロードするか、IBM SOA Sandbox のオンライン試用版を試してみてください。
議論するために
- XML 関連の Yahoo! Groups: ディスカッションに参加してください。
- XML ゾーンのディスカッション・フォーラム: XML 関連のフォーラムに参加してください。
- developerWorks コミュニティー: ここでは他の developerWorks ユーザーとのつながりを持てる他、開発者が主導するブログ、フォーラム、グループ、ウィキを調べることができます。
Betty Harvey は、Electronic Commerce Connection, Inc. の代表取締役を務めています。彼女は多数の政府機関および企業での構造化情報への移行計画および実行に関与してきました。現在は ebXML イニシアチブに参加し、『Professional ebXML Foundations』(Wrox、2001年) を共同で執筆した他、活発に執筆活動を行っています。また、首都ワシントンで SGML/XML Users Group を立ち上げ、このグループをまとめている傍ら、XML Guild のメンバーでもあります。Betty への連絡先は harvey@eccnet.com です。