本文へジャンプ

Lotus  >  Lotus Developer Domain  >  
   
 

LotusScript: Notes/Domino 6 における XML クラス (続き)

 
   
 
コンテンツ
はじめに
XSLスタイルシート
NotesをHTMLに変換する
Create HTML エージェント
DXLインポーターを使用する
他のフォーマットを生成する
リソース
筆者について(原文のまま)

David DeJean and Sally Blanning DeJean
DeJean & Clemens

レベル:上級
原文の掲載:2003年3月3日
更新日:2005年5月13日更新
原文はこちら


はじめに

5 部構成の第 3 部: Notes/Domino 6 の LotusScript における新規クラスと機能拡張に関するシリーズの続きとして、この記事では、Domino データを XML と HTML に変換する XSL 変換の例を紹介し、DXL インポーターを使用して XML を NSF 形式に変換する方法について解説します。
前の LDD Today の記事『LotusScript: Notes/Domino 6 における XML クラス』では、新規の LotusScript XML クラスと Domino データを DXL (Domino XML 言語) にエクスポートする DOM パーサーと SAX パーサーについて紹介しました。この記事ではその続きとして、DXL を他のマークアップ言語 (特に HTML) に変換する XSL トランスフォーマーと、XML を NSF 形式に変換する DXL インポーターの使い方を紹介します。この記事および前回の記事は、Notes/Domino 6 の LotusScript プログラミング言語における変更箇所を調べるシリーズの一部です。

この記事で参照したコードのサンプルは、Sandbox からダウンロードできます。サンプル・データベースを使用する前に、ローカルの C: ドライブに dxl ディレクトリーを作成してください。

XSLトランスフォーマーを使用する

XSL (XML Stylesheet Language) は、XML ファイルから異なる形式または異なるマークアップ言語へのフォーマット変換を制御する 1 つの方法です。Cascading Style Sheet を使用した経験があれば、XSL は似たようなものと言えるでしょう。どちらも同様のメカニズムで動作します。実際に、Web ブラウザーで表示するために、CSS スタイルシートを使用して XML ファイルを HTML に変換することができます。

データ変換のニーズはどこにでもあります。たとえば、ある会社では CRM (customer relationship management) データを Domino データベースに保存しているものとします。この会社が別の会社と業務提携をすると、顧客情報の一部を共有することが必要になります。相手の会社は、履歴データではなく、地域別の顧客情報を求めています。また、相手の会社では独自の CRM システムが使用されています。この場合、どのような方法でデータを渡しますか?もし、必要性が内部にとどまり、両方のシステムを完全に把握しているのであれば、Lotus Enterprise Integrator (LEI) を使用するとよいでしょう。しかし、相手の会社は外部の組織であり、こちらが把握しているのは自社のトランザクションについてのみです。このような場合は、XML を使用することが正解で、XSL 変換がキーになります。

Export Only Data-XSLTエージェント

前回の記事では、Domino データを DXL にエクスポートするエージェントを含む Hello World サンプル・データベースを紹介しました。この DXL Hello World データは連絡先レコードほど複雑ではありません。1 つのフィールドだけを持ち、そのデフォルト値は Hello World です。しかし、変換の原理は同じです。「5. Export Only Data-XSLT」という名前のエージェントは dxlhelloworld_data.xsl という XSL スタイルシートを使用し、DXL Hello World データベースから、最小限のデータだけを含む XML ファイルへのフォーマット変換を制御します。このエージェントのコードは、サンプル・データベースで見ることができます。このコードを実行するには、データベースからスタイルシートをコピーし (スタイルシートは共有リソースの [ファイル] セクションに保存されています)、前に作成した c:\dxl ディレクトリーに保存します。

エージェントの関連するセクションを以下に示します。最初のセットアップ後、2 つのストリーム・オブジェクト (1 つはスタイルシートを表し、もう 1 つは XML 出力ファイルを表します) を作成し、ファイルとパス名がすべて正しいかどうかをチェックします。

Dim XSL_ss As NotesStream  ' スタイルシート
Set XSL_ss=session.CreateStream
If Not XSL_ss.Open(pathname$ & filename$ &".xsl") Then
    Messagebox "Cannot open " & filename$,, "XSL file error"    
    Exit Sub
End If
Dim XML_out As NotesStream  ' 出力ファイル
Set XML_out=session.CreateStream
If Not XML_out.Open(pathname$ & filename$ & ".xml") Then
    Messagebox "Cannot create " & filename$,, "TXT file error"    
    Exit Sub
End If
XML_out.Truncate

エクスポートされるデータを文書だけに限定するために、前回の記事と同じ NotesNoteCollection コードを使用して、最初にデータベースから必要なものだけを抽出します。

Dim nc As NotesNoteCollection
Set nc = db.CreateNoteCollection(False)
nc.SelectDocuments=True
Call nc.BuildCollection

NotesDXLExporter が作成され、その入力が NotesNoteCollection の nc として指定されます。出力は指定されていないことに注目してください。

Dim exporter As NotesDXLExporter
Set exporter = session.CreateDXLExporter(nc) 

NotesXSLTransformer オブジェクトが、入力 (exporter)、スタイルシート (SXL_ss)、出力ファイル (XML_out) という 3 つの引数をともなって作成されます。NotesDXLExporter オブジェクトの exporter を XSL トランスフォーマーの入力として指定することにより、2 つのオブジェクト間にパイプラインが設定されます。

Dim exporter As NotesDXLExporter
Set exporter = session.CreateDXLExporter(nc) 

このエージェントを実行すると、SXL_ss スタイルシートを使用して DXL ファイルが変換されます。結果として、最小限の Domino データを表すファイルが得られます。

<?xml version="1.0" encoding="UTF-8"?>
    <database xmlns:dxl="    http://www.lotus.com/dxl    
    " numberofdocuments="1" dbid="85256C7500771804" 
    replicaid="85256C7500771804" path="dxlhelloworld.nsf"   
    title="DXL Hello World">    
    <database xmlns:dxl="    
    http://www.lotus.com/dxl    
    " numberofdocuments="1" dbid="85256C7500771804" 
    replicaid="85256C7500771804" path="dxlhelloworld.nsf"   
    title="DXL Hello World">    
    <document unid="2650244E74784BD985256C85004F5EDA" form="Hello">    
        <item name="HelloData">Hello World.</item>
    </document>    
    </database>

前回の記事のエージェントで作成されたファイルとこの出力を比較すると、要素が削除されているだけでなく、属性が要素間で移動していることに気づくでしょう。たとえば、database アイテムの numberofdocuments 属性と dbid 属性は、<databaseinfo> 要素内にありました。<document> 要素の unid 属性は、その子要素である <noteinfo> から移動されました。add と update のすべての <datetime> 要素は、なくなっています。

XSLスタイルシート

Export Only Data エージェントを実行するとき、LotusScript デバッガでは、上記のいずれのことも発生していないように見えます。exporter.Process の行に達すると、デバッガは「Magic happens here」と書かれたメッセージボックスを表示するでしょう。

実際に行われるのは、NotesXMLProcessor クラスの XSL Transformer エンジンが、エクスポーターから接続されている DXL にスタイルシートを適用することです。XSL スタイルシートを詳しく説明することはこの記事の目的ではありません。しかし、Hello World スタイルシートによってスターティング・ポイントとして使用できるコードが得られ、スタイルシートの基本的な記述方法がわかります。

基本として、XML 宣言、XSL 宣言、および出力宣言から開始します。

<?xml version="1.0" encoding="ISO-8859-1"?>
    <xsl:stylesheet xmlns:xsl="    
    http://www.w3.org/1999/XSL/Transform    
    " version="1.0"    
    xmlns:dxl='http://www.lotus.com/dxl'>    
    <xsl:stylesheet xmlns:xsl="    
    http://www.w3.org/1999/XSL/Transform    
    " version="1.0"    
    xmlns:dxl='http://www.lotus.com/dxl'>    
    <xsl:output method="xml" indent="yes"/>

注目したいのは XSL 宣言で、変換で使用される XSL オブジェクト用のネームスペースと、DXL オブジェクト用のネームスペースの 2 つの XML ネームスペースを指定しています。DXL 用のネームスペースは URL (http://www.lotus.com/dxl) のように見えますが、URL ではありません。URI にも似ていますが、実際にはそのようなものではありません。ブラウザーにこれを入力すると、エラー「404-File not found」が返されます。XSL ネームスペースの URI は少し異なり、XML および XSL ネームスペースに関する 2 つの W3C Web 文書を示します。

ネームスペースは、DTD と似ているところがあります。これはオプションの (そして、通常は仮想の) 文書で、XML 内の要素と属性に付ける名前にどのような意味を与えるのかを正確に定義します。ネームスペースを使用することの最大の利点は、ネームスペースの略語がスタイルシートで識別子として使用される点です。Hello World スタイルシートでは、接頭辞の xsl: は、この名前を持つアイテムを所有していることをトランスフォーマーに通知します。実際には、処理命令のこともあります。一方、接頭辞の dxl: は、DXL ファイル内で次の名前を検索するようトランスフォーマーに通知します。

スタイルシートは、コード内にほとんど動詞が含まれない構文によって記述されます。動詞 (match や select など) が使用されると、スタイルシートが、プログラミング言語というよりもデータベース検索のように見えます。実際に、XSL はワープロや Web ブラウザーの「検索」機能のような動作をします。XSL に対しては、ファイル内で何を検索するのかを指示します。検索対象を見つけた場合は、そこで現在のコンテキストを設定します。要素 <xsl:apply-templates select="dxl:database"/> を英語に翻訳すると「Find an element in the DXL file named 'database'」('database' という DXL ファイルで要素を検索する)となります。その場所で実行するアクションは、テンプレートによって指定されます。要素 <xsl:template match="dxl:database"> を英語で表現すると「When you locate an element named 'database,' perform the following actions.」('database' という要素を見つけたときは、次のアクションを実行する) になります。

トランスフォーマーには、いくつかのテンプレートが組み込まれています。スタイルシートはルート要素から実行を開始するので、たとえば、スタイルシートの最初の命令 <xsl:template match="/"> は検索命令ではなく、テンプレート化されたアクションの開始点になります (スタイルシートを開始させる要素として <xsl:apply-templates match="/"> を使用すると、組み込まれた一部のテンプレートが呼び出され、予期せぬ結果が出力されます)。

XSL テンプレートを記述するときは、スタイルシートをチェス・ゲームのような観点から考慮するとよいでしょう。select 要素によって、ボード内の別の場所に移動します。match 要素は、この新しい場所のコンテキストでアクションの処理を開始します。スタイルシート内の最初の select/match ペアは、次のようになります。

<xsl:template match="/">
<xsl:apply-templates select="dxl:database"/>
</xsl:template

<xsl:template match="dxl:database">
<xsl:element name="database">
<xsl:apply-templates select="dxl:databaseinfo"/>
<xsl:attribute name="replicaid"><xsl:value-of select="@replicaid"/></xsl:attribute>
<xsl:attribute name="path"><xsl:value-of select="@path"/></xsl:attribute>
<xsl:attribute name="title"><xsl:value-of select="@title"/></xsl:attribute>
<xsl:apply-templates select="dxl:document"/>
</xsl:element>
</xsl:template>

select によって、ルート要素から、DXL データ内にある database という名前の最初の要素まで移動します (実際には同じ要素かもしれませんが、それでもかまいません)。match 要素は、実際には if として働き、「一致した場合は、このテンプレートを次のものに適用する」ことを意味します。最初のアクション <xsl:element name="database"> によって、出力内に新しい要素が作成されます。次のアクションは、ボード内の別の場所に移動させる別の select ステートメントです。コンテキストは database 要素から、DXL 内の最初の要素である databaseinfo に切り替わります。検索は database という要素のコンテキスト内で開始されるので、そのスコープは database 要素のすべての子要素になります。databaseinfo という名前の要素が見つけられ、コンテキストがそこに移動します。一致したので、他のテンプレートが実行されます。

<xsl:template match="dxl:databaseinfo">
<xsl:attribute name="numberofdocuments">
<xsl:value-of select="@numberofdocuments"/>
</xsl:attribute>
<xsl:attribute name="dbid">
<xsl:value-of select="@dbid"/></xsl:attribute>
</xsl:template>

ここでも、最初の命令によって、出力内に新しい要素が作成されます。この要素は、numberofdocuments という名前の属性です。次の要素 <xsl:value-of select="@numberofdocuments"/> は、現在の要素である databaseinfo の属性で値を検索し (@ 記号で指定されます)、検索結果を出力に書き込みます。この後に、次の命令 </xsl:attribute> が続きます。これは、属性を終了させます (ステートメントの値は、選択された要素の子を常に返すことを思い出してください。どの要素の値のテキストも、XSL は子要素とみなします)。最後の命令は、dbid 属性を作成して出力します。そして、テンプレートが終了します。

LotusScript のサブルーチンと同様に、スタイルシート内でテンプレートを呼び出した地点に制御が戻ります。チェスボードの例では、database というアイテムの検索を行ったときにいたマス目に戻ることになります。もし、databaseinfo という名前の database の子要素がほかにもあるとすれば、これらの要素にもテンプレートが適用されます。しかし、実際にはそのような子要素はないので、コンテキストは database 要素に設定されたままになり、database に一致するテンプレート内の次の要素が実行されます。さらに、replicaid、path、title という 3 つの属性が出力に書き込まれます。次に、テンプレートは、document という要素に実行される別のテンプレートを呼び出します。

<xsl:template match="dxl:document">
<xsl:element name="document">
<xsl:apply-templates select="dxl:noteinfo"/>
<xsl:attribute name="form"><xsl:value-of select="@form"/></xsl:attribute>
<xsl:apply-templates select="dxl:item"/>
</xsl:element>
</xsl:template>

このテンプレートは、出力内に同じ document という名前の新しい要素を作成します。次に、noteinfo という子要素を検索します。noteinfo という子要素を持つ document が見つかると、別のテンプレートが実行されます。

<xsl:template match="dxl:noteinfo"> <xsl:attribute name="unid"><xsl:value-of
select="@unid"/></xsl:attribute> </xsl:template>

このテンプレートは document の unid を、noteinfo の属性ではなく、document の属性として出力に書き込みます。他の noteinfo フィールドが見つからない場合は、コンテキストが document に戻され、フォーム名が属性として出力に書き込まれます。テンプレートは、item という子を検索します。これは、Notes 文書内のデータ・フィールドです。

<xsl:template match="dxl:item">
<xsl:element name="item">
<xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>

テンプレートは、item という名前の各要素を検索し、item という名前の新しいアイテムを出力内に作成します。このとき、アイテムの名前 (この例では、Notes で割り当てられたフィールド名の HelloData) を保持する name という属性をともないます。次に、<xsl:value-of select="."/> という命令を使用して、アイテムの値を出力にコピーします。「.」は、this (これ) または here (ここ) を意味するコンテキスト上の参照子です。value-of 要素は一致する最初のインスタンスの値だけを返します。このため、アイテムは子要素 (「Hello World」という値) を 1 つだけ持つので、この要素は機能します。

これで、item テンプレートは終了します。コンテキストは document 要素に返されます。document の子アイテムはほかにないので、コンテキストは database 要素に返されます。database の子文書はほかにないので、コンテキストはルート要素に返されます。ルートの子データベースはほかにないので、すべてが完了します。

</xsl:stylesheet>

この結果を得るために使用した XSL スタイルシートは、あまり洗練されていません。XSL は、ここで説明する以上の能力を持つ言語です。サンプル・コードで示したこの数行と、NSF ファイルを DXL としてエクスポートする機能を利用すれば、CRM データベースを地域別にソートしたアドレス・リストに変換する方法のほか、これ以外のアプリケーションでの変換方法も理解できるでしょう。

NotesをHTMLに変換する

この XSL スタイルシートでの出力の宣言は「method = 'xml'」と記述されているので、トランスフォーマーは出力を整形式 XML として作成しました。「method = 'text'」と指定すると、テキストを出力するスタイルシートを書くことができます。同様に、「method = 'html'」と指定して、Web ページを出力するスタイルシートを書くこともできます。これは、Domino データを Web コンテンツに変換する LotusScript を作成できること意味し、たいへん興味深いことです。Web コンテンツは、Domino Server へのアクセスを必要とせずに、ブラウザー・ユーザーに提供されるので、セキュリティーあるいはパフォーマンスの面で稼働環境にプラスになる可能性があります。

Create HTMLエージェント

ここで 1 つの例を挙げましょう。Domino Designer でサンプル・データベースの dxlofficesupplies.nsf を開き、共有リソースの [ファイル] セクションにあるスタイルシート dxlofficesupplies.xsl を c: ディレクトリーにコピーします。Notes Client でこのデータベースを開き、Office Items ビューで左端の列をクリックして 6 つの文書を選択します。[アクション] メニューから [1. Create HTML] エージェントを実行します。エージェントは、選択された文書を文書コレクションに変換し、これを DXL としてエクスポートします。次に、dxlofficesupplies.xsl というスタイルシートをこれに適用し、HTML ページを作成します。この HTML ページは c:\dxl as dxlofficesupplies.html に保存されます。Create HTML エージェント全体の LotusScript コードは、Domino Designer で見ることができます。コードのほとんどの部分は、これまでに説明した例にたいへんよく似ています。最も大きな違いは、文書コレクションを作成するコードです。

Dim db As Notesdatabase
Set db = session.currentdatabase
Dim dc As NotesDocumentCollection
Set dc = db.UnprocessedDocuments
Dim exporter As NotesDXLExporter
Set exporter = session.CreateDXLExporter(dc)

ビュー内で選択された文書は、NotesDatabase の UnprocessedDocuments メソッドによって文書コレクションとして集められ、DXL エクスポーターの入力となります。これは、ユーザーによって選択された 1 つまたは数個の文書をエクスポートするシンプルでエレガントな方法です。

XSL スタイルシートの dxlofficesupplies.xsl は、HTML 文書に必要なタグを出力ストリームに書き出すテンプレートを使用して、この DXL の処理を開始します。スタイルシートの特定の行を出力にコピーするよう指定する必要がないことに注目してください。出力の宣言で HTML を指定したので、XSL トランスフォーマーは xsl: または dxl: で始まらないすべてのタグを出力対象の HTML として扱います。

<xsl:template match="/">
    <html>    
    <head>    
        <title>XSL-XML Demo</title>
    </head>    
        <body bgcolor="#ffffff" marginheight="0" 
        marginwidth="0" leftmargin="0" topmargin="0">        
        <br />        
        <center>        
        <xsl:apply-templates select="dxl:database"/>
    </center>    
    </body>    
    </html>
</xsl:template>

<apply-templates> 要素は DXL で <database> という要素によって一致されるので、次のテンプレートは <table> タグのセットと列見出しを出力に書き込み、DXL document 要素を検索します。

<xsl:template match="/">
    <html>    
    <head>    
        <title>XSL-XML Demo</title>
    </head>    
        <body bgcolor="#ffffff" marginheight="0" 
        marginwidth="0" leftmargin="0" topmargin="0">        
        <br />        
        <center>        
        <xsl:apply-templates select="dxl:database"/>
    </center>    
    </body>    
    </html>
</xsl:template>

DXL document 要素のテンプレートは、見つかった各 document ごとに表内で列を作成し、次に document 内の 2 つのアイテム (name と cost) 用にセルを作成します。そして、各 HTML 要素ごとに適切な終了タグを書き出します。

<xsl:template match="dxl:document">
    <tr>    
    <td width="5%"></td>    
    <td width="20%" bgcolor="336699">    
    <font face="arial" size="2" color="ffffff">    
        <xsl:value-of select="dxl:item[@name='Item']/dxl:text"/>
    </font>    
    </td>    
    <td width="5%" bgcolor="6699cc" align="right">    
    <font face="arial" size="2">    
        <xsl:value-of select="dxl:item[@name='Cost']/dxl:number"/>
    </font>    
    </td>    
    </tr>
</xsl:template>
</xsl:stylesheet>

コンテキストは他のテンプレートを介して戻るので、HTML 文書を完了させる他の終了タグが追加されます。スタイルシートは終了し、XSL トランスフォーマーは出力ストリームを閉じます。そして、エージェントは完了します。ビュー内で選択した Notes 文書の数に応じて、ブラウザーで HTML 文書を開くと次のような表示になります。

図 1. DXL Office Supplies のデモ



複数のHTMLページを作成する

複数の Notes 文書からデータを抽出し、1 つの HTML ページにまとめることは、特にレポート作成に役立つ手法です。しかし、Domino データベースの内容を個々の HTML ページとして書き出すことができれば、さらに効果的です。

この方法はセキュリティーとパフォーマンスの両面で有利で、組織における Web コンテンツの作成と配布が容易になります。DXL Office Supplies データベースの Create Multiple Pages エージェントのようなエージェントを使用すると、Notes データから HTML ページのセットを作成し、Web サーバーがアクセスできるドライブにこれらのページを保存することが可能です。スケジュール設定されたエージェントを用いて定期的にページを作成および更新し、Domino Server を使用せずにこれらを Web に提供できます。このとき、コンテンツの作成と編集の権限は、エージェントが置かれているデータベースの ACL で制御できます。

[2. Create Multiple Pages] エージェントは、dxlofficesupplies_multi.xsl という XSL スタイルシートを使用します。このスタイルシートは、前の例で使用した Create HTML Page と少しだけ異なっています。エージェントを実行する前に、このスタイルシートを DXL Office Supplies データベースの共有ファイルディレクトリーからコピーし、c:\dxl に保存してください。

エージェントは最初に、現在のビュー内のすべての文書を含む NotesViewEntryCollection を作成します。このビューの名前は Office Items です。

Dim view As NotesView    
    Set db = session.CurrentDatabase    
    Set view = db.GetView("Office Items")

エージェントは、DocNumb と DocCount の 2 つのカウンターを作成します。DocNumb は現在の文書が何番目の文書であるかを示す番号で、HTML ページの固有のファイル名を作成するために使用されます。DocCount はビュー内の文書数の合計を示します。Doc オブジェクトは現在の文書を表します。

Dim DocNumb As Integer    
    Dim DocCount As Integer    
    DocCount = view.EntryCount
    Dim Doc As NotesDocument
    Set Doc = view.GetFirstDocument
    DocNumb = 1

次に、Do While ループを使用して、入力と出力のストリームを作成するプロセス (つまり、エクスポーターと XSL トランスフォーマー) を繰り返し実行し、文書から HTML ファイルを書き出します。ファイルの書き出しが完了すると、DocCount をデクリメントし、DocNumb をインクリメントします。そして、次の文書を取得してループを実行します。

    Do While DocCount > 0 
  . . . . 
Call exporter.process

    DocCount = DocCount - 1
  DocNumb = DocNumb + 1
  Set Doc = view.GetNextDocument(Doc)
  Loop
  Exit Sub

エージェントによって呼び出される XSL スタイルシートの dxlofficesupplies_multi.xsl は、すべてのアイテムを 1 つの HTML ページにまとめるときに使用した前のバージョンと少しだけ異なっています。必要なデータは <document></document> タグ間に保持されているので、このスタイルシートはデータベースへのテンプレートの一致を省略します。このスタイルシートは、まったく同じ HTML コードを書き出します。今回は、1 つのエントリ行だけを含む表が生成されます。この行は、現在の文書に含まれる項目と価格を示します。

DXLインポーターを使用する

これまでは、Domino からデータを取得し、別の形式やアプリケーションに書き出す方法を説明してきました。しかし、LotusScript の XML 機能は、他のソースからデータを取得し、NSF ファイルに含めるという方法にも同じように有効です。このときに使用するのが NotesDXLImporter クラスです。

Import DXLエージェント

DXL インポーターは簡単に使用することができます。これを試すために、次に示す短い XML ファイルをコピーし、additems.xml という名前で c:\dxl ディレクトリーに保存してください。次に、DXL Office Supplies データベースで、[アクション] メニューから [1. Import DXL] エージェントを実行します。

<?xml version="1.0" encoding="utf-8" ?> 
    <database xmlns="    http://www.lotus.com/dxl    " version="6.0">    
    <document form="OF">    
        <item name="Item">        
            <text>Saddle stapler</text>
        </item>        
        <item name="Cost">        
            <number>38.85</number>
        </item>
    </document>    
    <document form="OF">    
        <item name="Item">        
            <text>Computer cleaning kit</text>
        </item>        
        HYPERLINK "C:\dxl\"  <item name="Cost">        
            <number>21.95</number> 
        </item>
    </document>    
    </database>

このデータに含まれていた 2 つの新規文書 (Saddle StaplerとComputer cleaning kit) を表示するために、Office Items ビューをすぐに更新する必要があります。Import DXL エージェントは、データ・ファイルを表す NotesStream オブジェクトを作成し、DXL インポーターを呼び出します。このとき、ストリームを入力として指定し、現在のデータベースを出力として指定します。

上記の XML データは DXL DTD に適合しているので、この処理はスムーズに進められます。要素名と親子関係は、同じ 2 つのアイテムがデータベースからエクスポートされたかのように、すべて同じになります (エクスポートされたデータにはすべて標準メタデータが含まれるはずですが、ここではそれが存在しなくても、インポーターにとって問題にはなりません。検出できないものに対しては、デフォルトが使用されるからです)。

しかし、インポートしたいデータが次のような場合はどうなるでしょうか。

<?xml version="1.0" encoding="utf-8" ?> 
    <database xmlns="    http://www.lotus.com/dxl    " version="6.0">    
    <document form="OF">    
        <item name="Item">        
            <text>Saddle stapler</text>
        </item>        
        <item name="Cost">        
            <number>38.85</number>
        </item>
    </document>    
    <document form="OF">    
        <item name="Item">        
            <text>Computer cleaning kit</text>
        </item>        
        HYPERLINK "C:\dxl\"  <item name="Cost">        
            <number>21.95</number> 
        </item>
    </document>    
    </database>

これは整形式 XML ですが、DXL ではありません。database タグはなく、sku や <manufacturer> など、Notes データベースに対応するものがないデータ要素があります。このため、解析とフォーマット変換が必要です。

Import Data - SAXエージェント

このケースでは、データ構造が比較的 DXL に近いので、SAX パーサー・エージェントを書くことができます (SAX パーサーについては、このシリーズの最初の記事で詳しく解説されています。SAX パーサーの詳細と NotesSAXParser クラスの使用例については、前の LDD Today の記事『LotusScript: Notes/Domino 6 における XML クラス』を参照してください)。サンプルのエージェントを実行する前に、上記のデータをコピーし、newitems.xml というファイルで c:\dxl ディレクトリーに保存します。その後、[アクション] メニューから、[4. Import Data - SAX] エージェントを実行します。2 つの新しいアイテムがビューに取り込まれます。

このエージェントはデータを DXL 形式で保存せず、パーサーからインポーターへのパイプラインとしてのみ機能します。もし、保存する場合は、保存されたデータは次のようになります。

<?xml version="1.0" encoding="utf-8" ?> 
    <database xmlns="    http://www.lotus.com/dxl" version="6.0">    
    <document form="FO">    
        <item name="SKU">        
            <number>123456</number>
        </item>        
        <item name="Item">        
            <text>Stainless steel stapler</text>
        </item>        
        <item name="Manufacturer">        
            <text>Acme Staplers</text>
        </item>        
        <item name="Cost">        
            <number>38.85</number>
        </item>
    </document>    
    <document form="FO">    
        <item name="SKU">        
            <number>6544321</number>
        </item>        
        <item name="Item">        
            <text>Computer screen cleaning kit</text>
        </item>        
        <item name="Manufacturer">        
            <text>Squeegee Enterprises</text>
        </item>        
        <item name="Cost">        
            <number>21.95</number>
        </item>
    </document>    
    </database>

これは、DXL DTD の構造に従います。<database></database> タグには、その他のすべてのデータが含まれています。各文書は <document></document> タグによって定義され、文書内の各データ・フィールドは、ネストされたタグのセットで定義されます。このセットは、<item name="n"></item> タグと、その内部にあってデータ型を定義する 1 組のタグ (この例の場合は <number></number> または <text></text> ) で構成されています。

Import Data - SAX エージェントはデータ・ファイルの newitems.xml を NotesStream オブジェクトとして開き、これを SAX パーサーに渡します。SAX パーサーはデータを DXL としてフォーマット変換し、DXL インポーターに渡します。

ファイルを NotesStream として開く
    Dim stream As NotesStream    
    Set stream = session.CreateStream   
    If Not stream.Open("c:\dxl\newitems.xml") Then
    Messagebox "Cannot open c:\dxl\newitems.xml. 
    Check to make sure this directory exists.",, "Error"
    Exit Sub
End If
'SAX パーサーを作成する
    Dim saxParser As NotesSAXParser    
    Set saxParser=session.CreateSAXParser(stream)
'DXL インポーターを作成する
    Dim importer As NotesDXLImporter    
    Set importer = session.CreateDXLImporter(saxParser, db)

イベント・ハンドラーの数が、最小限まで減らされています。

On Event SAX_StartElement From saxParser Call SAXStartElement    
    On Event SAX_EndElement From saxParser Call SAXEndElement    
    On Event SAX_Characters From saxParser Call SAXCharacters    
    On Event SAX_EndDocument From saxParser Call SAXEndDocument    
    On Event SAX_StartDocument From saxParser Call SAXStartDocument
    
    On Event SAX_Warning From saxParser Call SAXWarning
    On Event SAX_Error From saxParser Call SAXError
    On Event SAX_FatalError From saxParser Call SAXFatalError 

SAXStartDocument ハンドラーは、XML 宣言と <database> タグを出力にコピーします。

Sub SAXStartDocument (Source As Notessaxparser)
    Source.Output({<?xml version='1.0' encoding='utf-8'?>} + Chr(13)+Chr(10))    
    Source.Output({<database xmlns="    http://www.lotus.com/dxl" version="6.0">}_    
    + Chr(13)+Chr(10))
End Sub

対応する SAXEndDocument ハンドラーが、この両方のタグを閉じます。

要素を開始および終了させるイベントが中心のイベントになります。SAXStartElement ハンドラーが、重要な処理のほとんどを実行します。このハンドラーは、Select Case ステートメントを使用して、パーサーから返されたアイテムを要素名に基づいて処理します。

Select Case ElementName

要素の名前が、データのコンテナー要素を示す newitems の場合は、その要素は無視されます。

Case "newitems" 
Exit Sub 

要素名が <item> の場合、このサブルーチンは、文書が表示される Notes フォームの別名である「OF」を含む <document> タグを書き込みます。次に、このサブルーチンは sku 属性を名前付きアイテムの <item name="SKU"> に変換し、データ型を設定するために属性の値を <number> タグで囲みます。

    Case "item":    
    Dim i As Integer    
    Source.Output({<document form="OF">})    
    Dim attrname As String    
    For i = 1 To Attributes.Length    
        attrname = Attributes.GetName(i)        
        If Attrname="sku" Then        
Source.Output({<item name="SKU"><number>} 
+Attributes.GetValue(attrname) + {</number></item>>}) 
        End If
        Next 

<description> という要素は、DXL でこれに対応するもの、つまり Item というアイテムに変換され、後続の文字データ用に開始タグの <text> が書き込まれます。パーサーはデータ型の違いを識別できないので、データ型のタグは SAXCharacters ハンドラーではなく、ここに書き込まれます。また、文字データの前のアイテム名によって、文字データの型が何であるべきかを知ることができます。

Case "description": 
     Source.Output({<item name="Item"><text>}) 

price 要素は別に処理されます。この要素は <number> データ型の値を持つからです。

Case "price": 
    Source.Output({<item name="Cost"><number>}) 

最後に、データ内に現れる別のデータを Catch-all Else が処理します (このデータ・ファイルでは、Else に一致するのは manufacturer という名前のアイテムだけです)。要素名の大文字と小文字が適切に変換され、<text> データ型のアイテムの name 属性として使用されます。

    Case Else    
    nameProper$ = Strconv(ElementName, SC_ProperCase)    
    Source.Output({<item name="} + nameProper$ + {"><text>})    
    End Select

End Sub

SAXEndElement ハンドラーは、他の Select Case ステートメントを使用して各要素に適切な終了タグを書き込みます。

    Select Case ElementName    
    Case "newitems"    
    Exit Sub    
    Case "price":    
    Source.Output({</number></item>})    
    Case "item":    
    Source.Output({</document>})    
    Case Else    
    Source.Output({</text></item>})    
    End Select
    
End Sub

SAX パーサーの出力は DXL インポーターに渡されます。DXL インポーターは、2 つの新しいアイテムである「Computer screen cleaning kit」と「Stainless steel stapler」用の新規文書をデータベースで作成します。XML 入力からの 2 つのフィールドを持つ 2 つのアイテム用の Notes 文書 (SKU と Manufacturer) は、データベース内の他の文書には存在しません。

他のフォーマットを生成する

このサンプルでは、DXL と他の XML 言語間での変換を取り上げました。しかし、3 つのパーサー・ツールである SAX、DOM、および XSL をすべて使用すると、テキストを任意のフォーマットで生成できます。

Designer ヘルプ・ファイルのコード例を見ることにより、新規の LotusScript XML サポートが実行できる内容の一部を知ることができます。たとえば、ヘルプで NotesSAXParser クラスについて検索すると、XML ファイルを処理する際に各 SAX イベントごとにメッセージボックスを表示するエージェントが得られます。NotesDOMParser クラスのサンプル・コードはエージェントになっています。このエージェントは、サンプルの XML ファイルから作成した DOM ツリーで見つけたノードに関するテキスト・レポートを生成します。

DXL が公開するメタデータにはほとんど触れませんでした。しかし、DXL として利用できるデータは多数あり、ナレッジマネジメントなどを目的としたデータマイニングで活用できます。たとえば、データベースへの寄稿が最も多いユーザー、最新の寄稿を行ったユーザー、文書のアクセス日付の傾向 (顧客の動向、社員の生産性、収益の状況) などを調べる場合に利用できます。パーサー・ツールは、レポート用アプリケーションとして優れたポテンシャルを持っています。

まとめ

LotusScript の XML サポートにより、既存の重要な標準技術を用いてアプリケーションとシステム間でのデータ交換を行う、価値のある新しいツール・セットが Domino 開発者にもたらされます。この記事では、DOM、SAX、および XSL について、理解が必要な内容のすべてを解説することはできませんでした。しかし、LotusScript を使用して XML を扱う方法や、データを DXL (Domino XML 言語) としてインポートおよびエクスポートするサンプル・コードを紹介しました。また、DOM パーサー、SAX パーサー、および XSL トランスフォーマーを使用して、DXL を他の XML 言語との間で変換する方法についても解説しました。XML クラス、LotusScript の既存の優れた機能、DXL による Domino データベースの要素 (データとメタデータ) へのアクセス、これらを組み合わせることにより、LotusScript はデータ交換の強力なツールとなります。

リソース

Domino Designer 6 ヘルプ

筆者について(原文のまま)

Sally Blanning DeJean and David DeJean have been working with and writing about Lotus Notes and Domino for as long as they've existed. They were co-authors of the very first book about Notes, Lotus Notes at Work. Sally, a CLP Principal, has written other books about Notes and is a full-time Notes/Domino developer. David, a CLP, has been an editor and writer for several computer publications. He is a partner in DeJean & Clemens, a firm that develops Notes and Internet applications and technical and marketing communications.

上に戻る