まだプログラマーですが何か?

プログラマーネタ中心。たまに作成したウェブサービス関連の話も https://twitter.com/dotnsf

タグ:dxl

ずっと地味に開発を続けていて、先月くらいからブログで紹介し続けていたノーツデータベースのウェブ参照化ツール nsf2dxl2web 、ブログのおかげで日本語資料も整ってきたこともあり、招待制という形式ではありますがツールを公開することにしました。

#タイトル内容
1nsf2dxl2web の挑戦(1)nsf2dxl2web の目的や開発背景
2nsf2dxl2web の挑戦(2)nsf2dxl2web を構成する技術や仕組み
3nsf2dxl2web の挑戦(3)nsf2dxl2web の使い方を紹介
4nsf2dxl2web の挑戦(4)nsf2dxl2web のカスタマイズツール
5nsf2dxl2web の挑戦(5)nsf2dxl2web の全文検索ツールの使い方


裏で使われている技術とかの話を抜きにして簡単に説明すると「ノーツデータベース(.nsf)をリードオンリーのウェブ化」するツールです。例えばこんな感じのデータベースを、
17065f63


こんな感じにします。
e03d4c76


ビューや文書のレベルに加え、リッチテキスト内のリンクや添付ファイルといった要素も含めて再現します。ツール利用後は Nginx などの HTTP サーバーがあれば動かすことができます。「リードオンリーじゃ意味がない」という人へ、詳しくは上記のブログエントリ内を読んでいただきたいのですが、「編集もするならノーツ利用がおススめ」だからです。


いったん本ブログエントリを最後まで見ていただき、ただ単に「使ってみたい」という人はから、使った上で見た目のカスタマイズもしてみたい場合はも参照してみてください。どんなユーザー向けに、どういう想いを持って、どんな技術を使って開発したか、といった背景の部分にも興味ある方はぜひにも目を通していただきたいです。


ツールは現在も「開発中」という段階ではあるのですが、現在の主な作業はバグの修正で、それも最近はほぼなくなっています。どこかのタイミングでコードのリファクタリングを行って正式バージョンにしようかな、と考えている状態なので、かなり安定していると思っています。 自分以外の人が作ったノーツデータベースでも正しくウェブ化できるかどうかを調べたい時期になってきているので、完成度を更に高めたい、という意図もあります。

というわけで、以下の条件でツールを公開します:
(0)ノーツユーザーであること
(1)GitHub のプライベートリポジトリにアクセス権を付与する形で公開します。まず GitHub のアカウントを取得してください。
(2)利用を希望する場合、このブログのコメントか X(Twitter)facebook の僕のアカウントに DM する形でその旨を伝えてください。その際に GitHub のアカウントを教えてください。そのアカウントにアクセス権を付与します。
(3)nsf2dxl2web はオープンソースではありません。改変、譲渡、再配布はすべて禁止します。
(4)nsf2dxl2web を利用した結果に関しての補償はできません。
(5)nsf2dxl2web の利用時に必要なノーツクライアントや Node.js のセットアップは済ませておいてください。
(6)nsf2dxl2web の使い方カスタマイズ方法については上述の一連のブログ(日本語)、またはリポジトリ内の README.md (英語)を参照してください。使う前の時点でうまく動かなかったり、よくわからなくなってしまった場合はメールや DM での個別対応とさせてください。ツイッターでハッシュタグ #nsf2dxl2web を付けてツイートしていただいても構いません。
(7)nsf2dxl2web が期待通りに動かなかった(ノーツデータベースのウェブ化ができなかった)場合、報告の義務はないものとしますが、製品を改善する目的でその現象が再現するデータベースを使わせていただけると助かります


正直、用意したブログだけで(それ以外の事前情報なしで)セットアップを含めた動作確認ができるかどうか不安もあります。その人柱になっていただける人の募集と考えていただければと・・・ (^^;


#どこかで手順含めた動作デモをお見せできる機会があれば、馳せ参じますのでその旨ご連絡ください。


これらの記事の続きです:
nsf2dxl2web の挑戦(1)
nsf2dxl2web の挑戦(2)
nsf2dxl2web の挑戦(3)
nsf2dxl2web の挑戦(4)
nsf2dxl2web の挑戦(5)


ノーツデータベースのウェブ化ツールである nsf2dxl2web を紹介しています。5回目となる今回は検索編と位置付けています。 nsf2dxl2web そのものの機能紹介ではないのですが、nsf2dxl2web でウェブ化したデータベース内のビュー/フォルダや各文書を検索する仕組みをオープンソース全文検索サーバーである Fess を使って構築する手順を紹介します。なお一般的な Fess の使い方となるクイックスタートはこちらを参照ください:
https://fess.codelibs.org/ja/quick-start.html


まず、今回のために nsf2dxl2web を使って2つのノーツデータベースをウェブ化したサイトを以下に公開しました:
https://dotnsf.github.io/nsf2dxl2web_githubpages/

2023112602


アクセスすると上図のように2つのノーツデータベース(「NSF2DXL2WEB サンプル」と「サンプルDB」)をウェブ化したサイトが表示されます。この2つのノーツデータベースは私が nsf2dxl2web の動作テスト用に UI 含めて作ったものです(「サンプル DB」はリンク先のテスト目的で作ったものなので1文書だけのシンプルなものです。「NSF2DXL2WEB サンプル」にはサブフォームや添付ファイルを含めた様々なリッチテキスト要素が含まれています。前回説明しましたが、検索対象となることを想定してどちらも Standard UI のビュー/フォルダ形式にしています)。もともとノーツのワークスペース上に存在していた時の様子は以下なので、データベースアイコン含めて再現されていることが改めて確認できると思います:
2023112603


"NSF2DXL2WEB サンプル" と書かれたアイコンをクリックすると、選択したノーツデータベースを nsf2dxl2web を使ってウェブ化したページが表示されます:
2023112609


ではこのノーツデータベースをウェブ化した上記サイトを Fess で全文検索する手順を以下に紹介します。このサイトはパブリックに公開しているので、よかったら皆さんの Fess 構築作業(後述)の練習にも使ってみてください。


【Fess について】
FessJava で開発されたオープンソースの全文検索エンジンです。商用サポートのついたソフトウェアである N2SM Search のコミュニティ版、という位置づけです。

Fess は主に以下の機能が提供されています:
・ウェブのデータ収集と、収集したページの全文検索エンジン(今回紹介する機能)
・ファイルサーバーのデータ収集と、収集したファイルの全文検索
・データストア(CSV や RDB など)のデータ収集と、収集したデータの全文検索エンジン

Fess には Windows 版と Linux 版があり、Linux 版は rpm 形式や deb 形式でのパッケージ配布に加え、docker に対応したコンテナイメージも提供されています。本ブログエントリでは docker 版を使って構築手順を紹介します。


【Fess のインストール】
以下では docker 版の Fess をインストールする手順を紹介します。前提として docker (と docker-compose)がインストールされた x86_64 版の Linux 環境が必要になるため、自分の PC やクラウドサーバー上に用意しておいてください。

そして docker 導入済みの環境で以下のコマンドを実行して Fess を(正確には OpenSearch 版の Fess を)インストールします:
$ git clone https://github.com/codelibs/docker-fess.git

$ cd docker-fess/compose

$ sudo sysctl -w vm.max_map_count=262144

$ docker compose -f compose.yaml -f compose-opensearch2.yaml up -d
 または 
$ docker-compose -f compose.yaml -f compose-opensearch2.yaml up -d 

補足として、3つ目のコマンドを実行する理由はこの設定が推奨されていたためです。また4つ目のコマンドで実際に Fess を起動するのですが、Fess の検索機能で CORS の有効/無効を切り替えたい場合(Fess サーバーの外部から JavaScript で検索した場合などは有効にする必要があります)は4つ目のコマンドを実行する前に compose-opensearch2.yaml ファイルを編集して CORS コマンドの有効/無効を切り替えておく必要があります:
  :
services:
  es01:
    environment:
      - "api.cors.allow.origin=*"
      - "api.cors.allow.methods=GET, POST, OPTIONS, DELETE, PUT"
      - "api.cors.max.age=3600"
      - "api.cors.allow.headers=Origin, Content-Type, Accept, Authorization, X-Requested-With"
      - "api.cors.allow.credentials=true"
  :

最後のコマンドを実行すると Fess が起動します。初回のみイメージのダウンロードを伴うため時間がかかりますが、(イメージのダウンロードが済んだ)2回目以降はすぐに起動できるはずです。

Fess は 8080 番ポートで起動します。コマンド完了後に docker ホストの 8080 番ポートにアクセスし、以下のような画面が表示されればインストールが成功しています:
2023112604


デフォルトでは
 ユーザーID: admin
 パスワード: admin
のアカウントが作成されています。「ログイン」と書かれたリンクからログインします:
2023112605


初回ログイン時のみパスワードの更新が求められるので、新しいパスワードに更新します。以後、この新しいパスワードでログインしているものとして説明を続けます:
2023112606



【Fess で nsf2dxl2web サイトの全文検索インデックスを作る手順】
では Fess に(nsf2dxl2web で作ったウェブの)新しい検索インデックスを登録します。ログイン名の所をクリックし、「管理」を選択します:
2023112601


下のような管理画面が表示されます。画面左上にハンバーガーメニューがあることを確認します:
2023112602


ハンバーガーメニューから 「クローラー」-「ウェブ」 を選択します:
2023112603


ウェブのクローラー設定の一覧画面が表示されます(最初の状態では何も登録されていません)。ここに新しいウェブを追加するので、画面右上の「新規作成」をクリックします:
2023112604


ウェブクロールの新規設定画面が表示されます:
2023112605


ここに以下の内容を入力していきます(書かれていない項目はデフォルト値のまま):
・名前:(任意の設定の名称 例えば "NSF2DXL2WEB サンプル")
・URL:検索先ページの URL、上記例であれば "https://dotnsf.github.io/nsf2dxl2web_githubpages/49258A000002200B/index.html"
・クロール対象から除外する URL:(デフォルトから "|xml" を削除したもの)
・深さ:3

2023112606


なお、除外する URL から "|xml" を除いた理由ですが、デフォルト設定のままだと "xml" で終わる URL はクロールされないことになります。nsf2dxl2web でウェブ化したサイトの場合、各文書の URL は ".xml" で終わるので、このデフォルト設定のままだと文書データが検索インデックスに含まれなくなってしまいます。この状況を回避する目的でこの設定にしています。

また「深さ=3」を指定する意味ですが、ここでの「深さ」とは「ページ内のリンクを何段階まで辿るか」を意味しています。nsf2dxl2web でウェブ化した場合、対象 URL は index.html を指しているので、
 深さ=0:index.html のみ
 深さ=1:views.html (ビュー/フォルダ一覧)まで
 深さ=2:各ビュー/フォルダの HTML まで
 深さ=3:各文書まで(Standard UI の場合のみ)
を対象にクロールすることになります。というわけで、各文書のデータまで検索できるよう、ここでは「3」を指定しています。

設定できたら最後に「作成」ボタンをクリックします:
2023112607


ウェブのクローラー設定の一覧画面に戻ります。いま作成した設定が追加されていることを確認してクリックします:
2023112608


自動で付与された ID などを含め、作成した内容が表示されます。この登録内容を使い、「ジョブ」という単位でクロールを実行することになります。そのジョブを新規に作成するため、最下部の「新しいジョブの作成」ボタンをクリックします:
2023112601


画面に色々表示されますが、すべてデフォルト値のままで構いません。最下部の「作成」ボタンをクリックします:
2023112602


すると「ジョブスケジューラ」画面に切り替わり、今作成したジョブが追加されていることが確認できます。この作成されたジョブを選択します:
2023112603


※なお、このジョブスケジューラの一覧画面はハンバーガーメニューから 「システム」-「スケジューラ」 を選択することでも表示することができます:
2023112602


作成したジョブの内容が表示されます。ジョブの実行タイミングやスケジュールを指定することができるのですが、nsf2dxl2web でウェブ化したノーツデータベースの場合は(このシリーズの初回に背景として説明したように、ノーツデータベース側の変更が加わることはほとんどない想定でウェブ化されていることが多いと思うので)1回実行しておけば2度目は不要ということがほとんどだと思っています。ほぼこのままで問題ないはずですが、必要に応じて実行スケジュールを変更してください。

このジョブを実行するには最下部の「今すぐ開始」をクリックします:
2023112604


ジョブの実行が開始された、という旨のメッセージが表示されます。これで指定した内容でのクローリングが開始されています:
2023112601


ジョブの実行状況を確認する場合はハンバーガーメニューから 「システム情報」-「ジョブログ」 を選択します:
2023112602


過去に実行したジョブのログが一覧で表示されています。「状態」列が「実行中」となっている場合はジョブが実行中であることを意味しています:
2023112603


この値が「OK」になっているとジョブの実行が完了、つまりクロールが完了して、検索可能な状態になっていることを意味しています。状態が「OK」になっていない場合は「OK」になるまで待ちます:
2023112601


これを必要なノーツデータベースのぶんだけ繰り返します。今回の場合は「NSF2DXL2WEB サンプル」に加えて「サンプル DB」も Standard UI で用意しているので検索可能です。というわけでこちらのデータベースについても同様にインデックスを作成して検索ジョブを実行し、両方が完了している状態を作っておきました:
2023112602


なお、このサンプルのサイトの場合は(普通に公開されているので)不要ですが、検索対象先にベーシック認証がかかっている場合はハンバーガーメニューから 「クローラー」-「ウェブ認証」 を選択して、ウェブ認証情報を追加することも可能です:
2023112601


では検索インデックスが準備できたので、実際に検索してみます。Fess のトップページに戻り、適当なキーワード(下図では「タブ」)を入力後に Enter キーで検索してみます:
2023112601


検索結果の一覧が表示されます。ちゃんと全文検索できているので、ビューも文書も検索結果に含まれています:
2023112602


試しに検索結果のある文書をクリックすると、その文書が正しく表示されます:
2023112603


この例では複数のノーツデータベースの検索インデックスを有効にしていたので、複数のデータベースにまたがる検索が可能です。複数のデータベース内に含まれる検索ワード(下の例では「テスト」)を指定して検索した検索結果は異なるデータベースのものが含まれるはずです。ノーツデータベースでいうところの「串刺し検索」が可能になっていることを確認できます:
2023112604



以上、ノーツデータベースの参照ウェブ化ツールである nsf2dxl2web の使い方を、カスタマイズや検索機能まで含めて5回にわたって紹介してきました。ノーツデータベースを参照目的に絞ってウェブ化するツールですが、XSL を採用することでノーツの設計思想に近い形のままウェブ化でき、そのためカスタマイズ時にもフォーム単位でのカスタマイズが可能になっていたり、nginx やクラウド/コンテナ化を併用することで抜群のパフォーマンスが期待できたり、参照用途には必須の全文検索まで含めて実現できることが確認できています。

ノーツをほぼ参照目的だけで使い続けているケースではこういうウェブ化もアリなんじゃないかと思いながら作ってみた nsf2dxl2web がどこかで誰かの役に立つ日が来ることを願っています。


(過去記事はこちらです)
nsf2dxl2web の挑戦(1)
nsf2dxl2web の挑戦(2)
nsf2dxl2web の挑戦(3)
nsf2dxl2web の挑戦(4)
nsf2dxl2web の挑戦(5)




これらの記事の続きです:
nsf2dxl2web の挑戦(1)
nsf2dxl2web の挑戦(2)
nsf2dxl2web の挑戦(3)


ノーツデータベースのウェブ化ツールである nsf2dxl2web を紹介しています。前回は基本処理となる nsf2dxl と dxl2web 、そして簡易ウェブサーバーを使ってウェブ化されたコンテンツを確認する所までを紹介しました。

4回目となる今回はカスタマイズ編として、オプション機能として提供している2種類のカスタマイズ処理について紹介します。カスタマイズ不要で運用する場合は無視していただいてもいいのですが、「カスタマイズするとこんなことができるようになる」という程度でも知っておくと、思い通りの結果にならなかった場合の対応が楽になることもあるのでは・・と思っています。


前回、基本処理である(1)、(2)と(5)を紹介しているので、順番がおかしいように見えるかもしれませんが続きの(3)から紹介します。

【(3)customxsl.js】
この処理の説明をする前にこちらをご覧ください(特に画面の下半分):
2023111701


これ↑はノーツの標準テンプレートである「ディスカッション」から作ったデータベースを nsf2dxl2web を使ってウェブ化した結果から「すべての文書」ビュー内のある文書を開いた時の様子です。この文書が参照している MainTopic というフォームがうまく XSL に変換しきれていないため、UI が乱れてしまっています。ちなみに同文書をノーツクライアントで見ると下のように見えます:
2023111702


このように UI が乱れてしまう原因はいくつかあります。nsf2dxl2web のツール側でも可能な限り対応していくつもりではありますが、残念ながら 100% 再現できるようにするのは難しいと判断しています。その最大の原因は@式です。

@式はノーツが持つマクロ機能の1つです。このマクロがあることで柔軟な処理が実現できていることは事実だと思いますが、nsf2dxl2web のような変換ツールからすると酷な機能となっています。例えば nsf2dxl2web はノーツのフォーム内にサブフォームや共有フィールドが含まれていても(XSL との相性の良さもあって)UI を再現できるようになっています。しかし問題は例えば「サブフォームの参照先が@式の計算結果になっているようなケース」です。nsf2dxl2web は@式を無視するので、その計算結果がどのサブフォームを参照するべきなのかがわかりません。他にも@式の計算結果が含まれる設計要素を自動で正しく再現することはまだ 100% ではありません。それらの理由があり、上述のような UI の乱れが発生してしまうことがあります(いわゆる「ノーツの標準テンプレート」の類は設計要素内で@式が使われていることが多く、このような UI の乱れが発生しやすいと思っています)。

今回紹介する customxsl.js は、このように「自動処理だけでは再現できない UI をカスタマイズすることで修正する処理」を行う機能です。

nsf2dxl2web は標準で以下3つのノーツ標準テンプレート・カスタマイズ用の XSL セットを提供しています:
・メール
・ディスカッション
・ドミノディレクトリ(names.nsf)

nsf2dxl2web を展開したフォルダには customs というフォルダがあり、その中には
・mail
・disc
・names

という3つのサブフォルダがあるはずです。これらが上記3つの標準テンプレート・カスタマイズ用 XSL セットをそれぞれ含んでいます:
2023111703


ちなみにディスカッションテンプレート用のサブフォルダ(disc)の中には MainTopic.xsl と Response.xsl という2つの XSL ファイルが存在しています:
2023111704


これらのファイルの内容はそれぞれ以下のようになっています:
(MainTopic.xsl)
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="html" encoding="UTF-8"/> <xsl:template match="/"> <html> <head> <title><xsl:value-of select="document/item[@name='Subject']" /></title> <link href="../resources/nsf2dxl2web.css" rel="stylesheet"/> <script src="../resources/nsf2dxl2web.js"></script> </head> <body> <h1><xsl:value-of select="document/item[@name='Subject']" /></h1> <br /> <table border="1"> <thead> <tr> <th>Subject:</th> <th><xsl:value-of select="document/item[@name='Subject']" /></th> </tr> </thead> <tbody> <tr> <td>Categories:</td> <td><xsl:value-of select="document/item[@name='Categories']" /></td> </tr> <tr> <td>From:</td> <td><xsl:value-of select="document/item[@name='From']" /></td> </tr> </tbody> </table> <hr/> <p style="text-align:right;">(<xsl:value-of select="document/noteinfo/created" />)</p> <p><xsl:copy-of select="document/item[@name='Body']" /></p> </body> </html> </xsl:template> </xsl:stylesheet>
(Response.xsl)
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" encoding="UTF-8"/>
<xsl:template match="/">
<html>
<head>
<title><xsl:value-of select="document/item[@name='Subject']" /></title>
<link href="../resources/nsf2dxl2web.css" rel="stylesheet"/>
<script src="../resources/nsf2dxl2web.js"></script>
</head>
<body>
<h1><xsl:value-of select="document/item[@name='Subject']" /></h1>

<br />

<table border="1">
<thead>
 <tr>
  <th>Subject:</th>
  <th><xsl:value-of select="document/item[@name='Subject']" /></th>
 </tr>
</thead>
<tbody>
 <tr>
  <td>Categories:</td>
  <td><xsl:value-of select="document/item[@name='Categories']" /></td>
 </tr>
 <tr>
  <td>From:</td>
  <td><xsl:value-of select="document/item[@name='From']" /></td>
 </tr>
</tbody>
</table>

<hr/>

<p style="text-align:right;">(<xsl:value-of select="document/noteinfo/created" />)</p>

<p><xsl:copy-of select="document/item[@name='Body']" /></p>
</body>
</html>
</xsl:template>

</xsl:stylesheet>

詳しい説明は省略しますが、それぞれディスカッションテンプレートの MainTopic フォームと Response フォームを表示するための(シンプルな)XSL となっています。


ではディスカッションテンプレートから作られたノーツデータベースを例に実際に UI をカスタマイズする手順を紹介します。といっても作業はごくシンプルで、上述のように適用したいフォームの UI 定義が記載された XSL ファイルを必要なフォームの分だけ(フォーム名).xsl というファイル名で用意し、一つのサブフォルダ(この例だと disc)内に格納しておきます。なお(フォーム名)部分は大文字小文字も正しく指定する必要があります。

その上で以下のコマンドを customxsl.js ファイルが存在しているフォルダ上で実行します:
$ node customxsl (対象の DXL が出力されているフォルダ) (カスタム XSL ファイルが格納されているフォルダ)

2023111705


すると上図のように指定した DXL フォルダ内の全文書に対して、その文書が参照しているフォーム定義を見つけ、そのフォーム定義を指定したカスタム定義用フォルダ内の XSL を適用して置き換えます。これによって dxl2web.js で作ったフォームの XSL ではなく、あらかじめ用意したフォームの XSL が使われるようになります。なお、この処理を実行後に再度同じデータベース内文書をウェブブラウザで見ると、以下のように(シンプルな見栄えではありますが)UI が乱れることなく表示することができるようになります(MainTopic フォームだけでなく Response フォームも書き換わっています):
2023111706


なお、この3つの標準テンプレートのカスタマイズサンプルに限って MIT ライセンスでのオープンソースとします(ビジネス利用含めて改変可)。また提供されている3つ以外のデータベースに対しても同様に(そのデータベース内に含まれるフォームの XSL を用意すれば)この customxsl.js を使ってカスタマイズ可能です。


【(4)viewhtml.js】
もう1つのカスタマイズツールが viewhtml.js です。上述の customxsl.js は文書の UI をカスタマイズするツールでしたが、こちらはビュー/フォルダの UI をカスタマイズします。ただ customxsl.js では独自の XSL を用意して文書の UI をフルカスタマイズすることができましたが、ビュー/フォルダの UI については以下の2種類用意していて、そのどちらを使うかを切り替えるツールという位置づけです:

・Simple UI(デフォルトはこちら)
・Standard UI

デフォルトでもある Simple UI はビューに含まれる文書の一覧を簡易的な検索機能とページネーションによって表示する機能を持っています。この検索やページネーションには jQuery を併用した JavaScript で動的に行っています(そのためビュー描画の処理が軽くなっています)。大きな制約事項として別途検索エンジンを使って検索機能を実装しようとした際に(JavaScript で動的に文書リストを取得しているので)HTML 自体には文書へのリンクが含まれないため、各文書がクロール対象にならない(検索対象にならない)、という制約があります。

一方の Standard UI は全文書を一枚の HTML 内で静的に表示します。DataTables も有効になるため、簡易検索に加えてビューの列を指定したソートなど、Simple UI にはない便利な機能が含まれます。この構成の場合、HTML 内に全文書へのリンクも含まれるので検索エンジンのクローラーが文書レベルでのクロールもしてくれます(つまり各文書が検索対象になります)。一方、数万個レベルの文書が含まれるようなビュー/フォルダの場合、HTML 内で対象となる文書数が非常に大きくなるため、描画が非常に重くなります(場合によってはブラウザが out of memory エラーとなります)。「デフォルトで Standard UI がいい」と思う人もいらっしゃると思いますが、このような影響の大きい制約事項があるため、デフォルトの挙動としては Standard UI を採用せずに Simple UI を採用しています。


この Simple UI と Standard UI を切り替えて表示したい場合に viewhtml.js を使います。切り替えを行うには viewhtml.js のあるフォルダで以下のコマンドを実行します:
$ node viewhtml (対象の DXL が出力されているフォルダ) (standard または simple)

前回ウェブ化したデータベースを Standard UI に変換してみます:
2023111801


この状態で(Standard UI で)ビューを参照すると以下のようになります。DataTables が有効なページネーションやフィルタリング(簡易検索)、テーブル列毎のソート機能が有効になった状態で全文書(つまりビュー/フォルダに含まれる全文書)へのリンクが含まれています:
2023112601


変換前の同じビューも比較のために載せておきます。デフォルトの Simple UI の場合はこちらでした(Standard UI よりも少しシンプルになっているのがわかると思います):
2023111803


詳しくは次回の記事で説明する予定ですが、クローラー型の検索エンジンを併用してウェブ化されたコンテンツを運用する場合、Standard UI の状態でないと(HTML 内に各文書への静的なリンクが含まれた状態でないと)文書が検索対象になりません。一方で Standard UI は文書数が数万レベルになると(ノーツデータベースの場合は結構ありえると思ってます)ビュー参照時にブラウザが out of memory エラーを起こしてビューが表示できない(したがって文書にもアクセスできない)ことが起こりえます。

というわけで、検索エンジン併用運用の場合は、
・いったん Simple UI から Standard UI に変更して、
・Standard UI の状態で検索エンジンのクローラーでクローリングして、
・クローリングが完了したら(必要に応じて) Simple UI に戻す
という処理をすることをお勧めします。


nsf2dxl2web の機能に関してはここまでで概ね紹介できたと思っています。次回は nsf2dxl2web からは少し離れますが、ここで少し紹介したようなウェブ化した複数データベースによるコンテンツを検索エンジンで全文検索する際の例を紹介するつもりです。



(過去記事や続きはこちらです)
nsf2web2dxl の挑戦(4)



これらの記事の続きです:
nsf2dxl2web の挑戦(1)
nsf2dxl2web の挑戦(2)


三回目となる今回は使い方編と位置づけ、 nsf2dxl2web の使い方を紹介します。2023-11-26 の現時点ではまだツールは(招待制のみでの)非公開ですが、一部の人から徐々に使っていただくことを想定していて、その時に使い方を知ってもらうための紹介ページのつもりで作ります。

なお nsf2dxl2web は今後段階的に公開していく予定ではありますが、オープンソース化の予定は今のところありません。ツールの改変も原則認める予定はありません(次回紹介予定のカスタマイズツールで提供しているサンプルのみ改変しての利用を認めます)。

また将来的に今後の改善や変更によって UI 含めて、ここで紹介している内容と異なる部分がでてくるかもしれない、という点をご了承願います。


【前提条件】
nsf2dxl2web は以下のツール類がインストール/セットアップされている条件の下で動作します:
・HCL ノーツ(バージョン8以降であれば動くと思いますが、バージョン 10 で動作確認しています)
Node.js(バージョン 16 で動作確認しています)

また nsf2dxl2web が変換対象とするノーツデータベースのサイズによっては動作中にメモリ不足が発生する可能性があります。当方では 16GB のメモリを搭載した Windows 11 PC で動作確認しており、この環境下でファイルサイズが約 12 GB のノーツデータベースの変換に成功した実績はあります。なおその際は notes.ini に以下の1行を追加して(ノーツ実行時の Java ヒープサイズを 512MB に増やして)実行しています:
JavaMaxHeapSize=512MB

ちなみに nsf2dxl2web を動作させるだけであればドミノサーバーは不要です(ノーツのセットアップ時に必要になるはずです)。

また後述の(1)および(2)の処理を実行するためには実行するマシンがインターネットに接続している必要がある点に注意してください。


【nsf2dxl2web ツールの取得】
いずれ GitHub リポジトリを公開して URL をここに記載する予定ですが、現時点ではプライベートリポジトリで運用しています。お手数をおかけしますが、しばらくの間は個別にリポジトリのアクセス権を与えられた後に該当 URL から git clone するか、zip でダウンロード/展開してください。


【nsf2dxl2web ツールに同梱されているもの】
ツール一式には nsf2dxl2web 本体を含めた数多くのファイルが含まれています。その中で利用者が明示的に使うことになる(可能性がある)ファイルは以下の6つです:
(1)nsf2dxl2web.nsf
(2)dxl2web.js
(3)customxsl.js
(4)viewhtml.js
(5)web.js
(6)README.md


(1)の nsf2dxl2web.nsf はデフォルトで参照権限のついたノーツデータベースで、この中に nsf2dxl エージェントが含まれています。利用者はこのデータベースをノーツで開き、アクションメニューから nsf2dxl エージェントを実行後に対象データベースを指定して nsf2dxl 処理を行います(詳しくは後述):
2023111601

なお、このデータベースを起動した時に開く「アプリケーションについて」文書の内容は(6)の README.md の内容と同等です。

(2)の dxl2web.js は dxl2web 処理を行う Node.js アプリケーションです。(1)の nsf2dxl と、(2)の dxl2web の2つの処理によって nsf2dxl2web を実現します。

(3)の customxsl.js は(2)の結果として生成された静的コンテンツの文書の見た目をカスタマイズする処理で、これも Node.js アプリケーションです。文書データの UI カスタマイズが必要な場合に使います。

(4)の viewhtml.js は(2)や(3)の結果として生成されたビューやフォルダの UI をカスタマイズする処理で、これも Node.js アプリケーションです。ビューやフォルダの UI カスタマイズが必要な場合に使います。

(5)の web.js は(2)や(3)、(4)の結果生成された静的コンテンツを表示するウェブアプリケーションで、これも Node.js アプリケーションです。これを使って運用してもよいのですが、どちらかというと出来上がった静的コンテンツの見た目を一時的に確認するテスト用ウェブサーバーというつもりで同梱しています(実際の運用ではウェブサーバーとして nginx などを使うことを想定しています)。

(6)は一通りの説明(英語)を含めた README.md です。使い方も記述していますが、英語が苦手な人もいると思うので、今回このブログエントリを書いています。


【nsf2dxl2web の各ツールの使い方】
以下、上述(1)~(5)の各ツールの使い方を紹介します。

【(1)nsf2dxl2web.nsf】
ノーツデータベース(nsf)を XML データ(dxl)として出力します。厳密には単に nsf を dxl 化するだけではなく、ビューデータの CSV 化なども含んでいますが、ここではすべて含めて「nsf2dxl 処理」と呼ぶことにします。

(1)の nsf2dxl2web.nsf をノーツクライアントで開きます:
2023111713


以下のようなセキュリティ警告ダイアログが表示された場合は「署名者を信頼する」を選択して実行してください:
ノーツ_実行セキュリティ警告


ちなみにこのデータベースにはフォームやビュー、文書は登録されていません。エージェントと、そのエージェントが参照するスクリプトライブラリが登録されているだけです。

起動オプションによって、このような「アプリケーションについて」文書が表示されます:
2023111602


この状態から nsf2dxl エージェントを実行するのですが、実行ログを表示できるように Java デバッグコンソールを表示しておきます。メニューから「ツール」-「Java デバッグコンソールの表示」を選択します:
2023111603


下図のようなウィンドウが表示されます。この後に実行する nsf2dxl エージェントの実行ログはこのウィンドウ内に表示されるので、途中で(out of memory などの)エラーが発生した場合はこのウィンドウ内に出力されるので、思っていたような結果にならない場合はこのウィンドウ内に表示されるメッセージを参照してみてください:
2023111604


では nsf2dxl エージェントを実行します。メニューから「アクション」-「nsf2dxl」を実行します:
2023111601


以下のようなデータベースを選択するダイアログ(タイトルは「開く」)が表示されます。ここでウェブ化したいデータベースを選択します:
2023111605


ちなみにここで指定しているデータベースはワークスペース上ではこのように表示されているものを使っています。後でウェブ上でどこまで再現されているかを確認してください:
2023111706


データベースファイルを選択すると、そのファイルをエクスポートする先のフォルダを指定する別のダイアログ(タイトルは「保存」)が表示されます。nsf2dxl2web の処理が完了すると、ここで指定したフォルダがウェブのコンテンツルートになるフォルダなので、初めて nsf2dxl を実行した場合は中身が空のフォルダ(2回目以降は初回に指定した時と同じフォルダ)を指定します。フォルダを指定したら(下図では C:\tmp\tmp)保存ボタンをクリックします:
2023111606


すると指定したデータベースファイルに対して nsf2dxl エージェントが実行され、その結果が指定したフォルダ(上の例だと C:\tmp\tmp)内にエクスポートされます。同時に実行ログが Java デバッグコンソールに表示されます:
2023111607


実行結果は指定したフォルダ内に「指定したデータベースのレプリカID」のサブフォルダが作られ、その中に(上の例だと C:\tmp\tmp\49258A000002200b\ フォルダ内に)出力されていきます。この出力先フォルダ名はログの3行目にも表示されています。 また最後の行に "Processing Step.2 done." と表示されていますが、この行が表示されていれば nsf2dxl 処理が正しく実行できたことを意味しています。

この時点で出力先フォルダの様子を見ると、中には "(指定したデータベースのレプリカID)_designs.xml" というファイル(この中にフォームやイメージリソースなどの設計要素の情報が含まれています)と、"(ビュー/フォルダの UNID).csv" というファイル名でデータベース内の全ビュー/フォルダの情報が CSV 形式でエクスポートされている様子が分かります:
2023111608

また "documents" というサブフォルダが作られていて、このフォルダ内にはデータベース内の全ての文書が "(文書の UNID).xml" というファイル名で出力されている様子が確認できます:
2023111609


nsf2dxl 処理が成功するとこのような結果になります。ビュー/フォルダの数や、含まれる文書数によって実行にかかる時間や出力結果のファイル数や各ファイルのサイズが異なりますが、"Processing Step.2 done." というログが最後に出力されていれば成功です。逆に途中で "Out of memory" などのエラーが表示されている場合は(上述の方法でヒープメモリを確保するなどの対処をして)再度実行する必要があります。

これで nsf2dxl の処理は完了ですが、まだ dxl2web の処理ができていないため、まだウェブでの参照はできません。ただここまででノーツクライアントを使った処理は完了です。これ以降の処理はすべて Node.js がインストールされた環境下で行うことになります。


【(2)dxl2web.js】
前述の nsf2dxl でエクスポートしたデータをウェブ化します。ここでの「ウェブ化」の意味は「静的サイト化」ですが、動的な XSLT 処理で HTML を生成するため、いわゆる HTML ファイルはあまり多く作られません(文書データはすべて XML データとなります)。

まずはシェルやコマンドプロンプトなどのターミナルを起動し、cd コマンドを使って nsf2dxl2web を展開したフォルダ(dxl2web.js があるフォルダ)に移動します:
2023111701


最初の一回だけは nsf2dxl2web を利用する上で必要な依存ライブラリをインストールする必要があります。依存ライブラリのインストールは dxl2web.js のあるフォルダで "npm install" を実行します:
2023111702


依存ライブラリがインストールできれいれば dxl2web.js を実行することができます。カレントディレクトリを dxl2web.js があるフォルダに変更した後に以下のコマンドを入力します:
$ node dxl2web (1)の処理で DXL を出力した先のフォルダ名

上記例では最後のフォルダ名が C:\tmp\tmp\49258A000002200B だったのでこのフォルダ名をフルパスで指定します。dxl2web.js が実行され、最後に "done" と表示されていれば処理は成功しています(対象データベース内の文書数が数百件程度であれば一瞬で終わりますが、数万レベルだと、この処理は結構時間がかかります):
2023111703


あっけない感じですが、これでデータベースのウェブコンテンツ化が(一応)完了しました。


【(5)web.js】
ウェブコンテンツ化された内容に対してカスタマイズを行うこともできるのですが、それは次回に説明するとして、まずはウェブコンテンツ化された内容をブラウザで表示してみましょう。そのためのツールが web.js です。

web.js を実行前に環境変数を指定します。まず環境変数 CONTENTS_ROOT に nsf2dxl 実行時に指定した結果出力先フォルダ名(レプリカ ID を含まないもの)を、Windows の場合は "\" マークを "/" にしたものを(今回の場合だと "/tmp/tmp" を)指定します。またこれはオプションですが、起動する HTTP サーバーのポート番号(無指定時のデフォルト値は 8080)を環境変数 PORT でそれぞれ指定します:
2023111704


この状態で 
$ node web
を実行します。指定したポート(上の例だと 8000 )で HTTP サーバーが待ち受ける状態になります:
2023111705


この HTTP サーバーにアクセスしてみましょう。ウェブブラウザで(この例の場合であれば) "http://localhost:8000" にアクセスしてみます:
2023111707


(1)の処理で指定したノーツデータベース名がアイコンと共に表示されているはずです。ではこのアイコンをクリックします:
2023111708


新しいタブが開き、その中で↑のような画面になります。画面は3分割されていて、それぞれ以下が表示されるフレームになっています(最初は左上のフレームだけが表示されていて、ここにデータベースの全ビュー/フォルダ、および「アプリケーションについて」「アプリケーションの使い方」へのリンクが表示されています):
2023111709


左上のフレームでいずれかのビュー/フォルダを選択すると、右上のフレームでそのビュー/フォルダが表示されます:
2023111710


そして右上のフレームでいずれかの文書を選択すると、下のフレームにその文書が表示されます:
2023111711


ちなみに同じデータベースの同じビューと同じ文書をノーツクライアントで選択するとこのようになります。画像やフォントなどが再現されている様子が確認できると思います:
2023111712


前回のブログエントリでも紹介しましたが、この文書データが表示される際に XSLT 処理が実行されています。文書データはあくまで XML データ(UI を持たないデータ)としてエクスポートされていますが、表示時にフォームの XSL が適用されることで、このように元のノーツ文書に近い UI が再現できています。


【他のデータベースにも適用】
上述した(1)の nsf2dxl 処理と(2)の dxl2web 処理を他のデータベースに対しても実行すると、対象になったデータベースすべてをウェブ化することができます。仮に5つのデータベースに同様の処理を行った後に HTTP サーバーにアクセスすると、以下のように5つのデータベースのアイコンと名前が(ノーツのワークスペースのような感じで)表示されるようになります:
2023111714


各アイコンをクリックすると新しいタブが開いて同様にウェブ化されたコンテンツを表示することができます:
2023111715


このシリーズの初回でも触れましたが、データベース間のリンクも再現できるようになっています。あるデータベースA内の文書の中で、別のデータベースB内のビューや文書へのリンクが作られていた場合、データベースAとB両方がこの nsf2dxl2web ツールによってウェブ化されていれば、ビューリンクや文書リンクもウェブ上で再現できます(わかりにくいと思いますが、↑の例で最初にウェブ化したデータベース内の文書からもう1つのデータベース内の文書にリンクが張られていて、そのリンクをクリックすると文書フレームの内容だけ別データベースの文書になっています):
2023111716


長くなってしまったのでいったんここまでにします。次回はカスタマイズ機能について紹介する予定です。



(過去記事や続きはこちらです)
nsf2web2dxl の挑戦(3)




この記事の続きです:
nsf2dxl2web の挑戦(1)


上記記事では自分が開発中(公開予定)のツール nsf2dxl2web の概要を紹介しました。第2回目である今回は技術編と位置づけ、 nsf2dxl2web が動作する仕組みについて紹介します。現時点(2023-11-07)ではまだツールそのものを公開しておらず、試すことができないため仕組みの紹介もわかりにくい点があるかもしれませんが、どのような仕組みで、どのような変換を行うのか、その理解の上で必要な知識である XSLT も交えて紹介したいと思います。


【2つのツール+オプション】
nsf2dxl2web は主に nsf2dxldxl2web という2つのツールから構成されていて、これらに加えオプションとして更にいくつかの補助ツールが用意されています。ツール名に含まれる "nsf" というのは(ノーツデータベースファイルの拡張子が "nsf" であることから)ノーツデータベースのことを指しています。ノーツデータベースに対してまず nsf2dxl(NSF to DXL) の処理を行うことでノーツデータベースを DXL(Domino XML Language) という XML の派生フォーマットに変換します。 その結果である DXL に対して dxl2web(DXL to Web) の処理を行ってウェブ化(ウェブコンテンツ化)する、という2段階の処理を続けて行います。この NSF to DXL と DXL to Web の2段階の処理をそれぞれ nsf2dxl と dxl2web を使って行うことになります。



【DXL】
上述の説明内にも出てきた DXL(Domino XML Language) は知らない人も多いと思うので補足しておきます。DXL は Domino(ノーツサーバー)が管理するデータベース内の文書データや設計要素を domino.dtd のルールに従って XML フォーマットで記述したものです。ノーツの拡張機能である LotusScript や Java を使ってデータベース(の全体または一部)を DXL フォーマットで出力したり、DXL で記述された情報からバイナリデータであるノーツデータベースに変換することができます。

nsf2dxl2web を使う上で DXL の最大の特徴は「テキストファイル」であることです。バイナリデータであるノーツデータベースファイルはノーツクライアントまたはノーツサーバーを使って正しい権限の ID でログインした上でないと開いて中身を確認することもできませんが、DXL(つまり XML)になっていればテキストエディタで開くこともできるようになります。

nsf2dxl2web はこの名前の通り、nsf(ノーツデータベース)をノーツの機能を使って一旦 dxl(XML テキスト)に変換(nsf2dxl)した上で、再度 dxl を web コンテンツに変換(dxl2web)することで一連の変換処理が完了します。


【XML と XSL(と XSLT)】
上述の DXL の説明内で「nsf を dxl に変換」し、「dxl を web コンテンツに変換」すると書きました。前者の処理はノーツが持つ DXL エクスポート機能を使うことでできるのですが、後者の処理(UI を持たない XML を UI 付きの HTML へ変換)はどのようにするのでしょう? この答が「XSL を使って XML を HTML に変換する」です。

XSL(eXtensible Stylesheet Language)  は XML というフォーマットに従って作られた文書(XML 文書)に対して、その構造や表示方法を印刷および閲覧に適した状態に整える、その見栄えを定義するマークアップ言語です。XSL 自体も XML の拡張として定義されています。また「XML を XSL を使って印刷および閲覧に適した状態に整える」この変換処理のことを XSLT(eXtensible Stylesheet Language Transformation) と呼びます。

具体例があった方がわかりやすいと思うので、簡単な例を紹介します。まず以下のような XML データ(test01.xml)があったとします:
<?xml version="1.0" ?>
<成績表>
  <見出し>成績表</見出し>
  <結果 名前="佐藤" 国語="50" 数学="90"/>
  <結果 名前="鈴木" 国語="70" 数学="60"/>
  <結果 名前="田中" 国語="80" 数学="40"/>    
</成績表>

この程度であれば UI がなくてもなんとなく全容が見えてくる XML データだと思っています。クラスの科目別成績表のようなデータが XML フォーマットで格納されている、と思っていただくのがいいでしょう。

この XML データに対して、以下のような XSL (test01.xsl)を適用することを考えてみます:
<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html"/>
<xsl:template match="/">
<html>
<head>
<title><xsl:value-of select="成績表/見出し" /></title>
</head>
<body>
<h1><xsl:value-of select="成績表/見出し" /></h1>
<table id="mytable">
<thead>
<tr><th>名前</th><th>国語</th><th>数学</th></tr>
</thead>
<tbody>
<xsl:for-each select="成績表/結果">
<tr>
  <td><xsl:value-of select="@名前" /></td>
  <td><xsl:value-of select="@国語" /></td>
  <td><xsl:value-of select="@数学" /></td>
</tr>
</xsl:for-each>
</tbody>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

XSL にあまり詳しくなくても、この例をみると何となく結果がイメージできるのではないでしょうか? XSL の中に <xsl:template match="/"> ~ </xsl:template> で囲われた箇所があり、この中に変換元である XML(上述の test01.xml)の "/" にマッチする部分(つまり全体)が適用されて変換されます。 そしてこの箇所には <xsl:value-of select="成績表/見出し" /> と書かれた部分が2か所存在しています。この部分は変換元 XML(test01.xml)の "/" にマッチした部分(つまり全体)の中の、"成績表/見出し" 要素(つまり "/成績表/見出し" 要素)の値が適用されることになります。変換元 XML (test01.xml)を見ると "/成績表/見出し" 要素の値というのは「成績表」という文字列です。つまりこの例だと <xsl:value-of select="成績表/見出し" /> 部分には「成績表」という文字列が入ることになります。

また、この XSL 内には <xsl:for-each select="成績表/結果"> ~ </xsl:for-each> で囲われた箇所もあります。変換元 XML(test01.xml)の "/成績表/結果" は複数存在しています。つまり全ての "/成績表/結果" 要素に対してループを行っている、ということが何となくわかるのではないかと思います。

そしてそのループの中では上述と同様の <xsl:value-of match="@名前"/> 、<xsl:value-of match="@国語"/> 、<xsl:value-of match="@数学"/> という値を取り出している箇所がありますが、これらはそれぞれループ内の要素から「名前属性値」、「国語属性値」、「数学属性値」をそれぞれ取り出して適用する、という内容が定義されています。

そして、この XML(test01.xml)に XSL(test01.xsl)を適用した XSLT の結果は以下のような HTML になります:
<html>
<head>
<title> 成績表 </title>
</head>
<body>
<h1> 成績表 </h1>
<table id="mytable">
<thead>
<tr><th>名前</th><th>国語</th><th>数学</th></tr>
</thead>
<tbody>
<tr>
  <td> 佐藤 </td>
  <td> 50 </td>
  <td> 90 </td>
</tr>
<tr>
  <td> 鈴木 </td>
  <td> 70 </td>
  <td> 60 </td>
</tr>
<tr>
  <td> 田中 </td>
  <td> 80 </td>
  <td> 40 </td>
</tr>
</tbody>
</table>
</body>
</html>

↑これが XML と XSL による XSLT です。XSLT という処理がノーツの文書とフォームの関係に近い処理をしていることがお分かりいただけるでしょうか。

そして XSLT が理解できているとなんとなく想像できると思いますが、nsf2dxl2web というツールを使うことで、
・ノーツの文書 DXL (XML) データとフォームの DXL データを取り出し、
・ノーツ文書の DXL データと
・フォームの XSL データを使って、
・これらを XSLT することで、ノーツ文書の HTML を生成する

という方法でノーツデータベースのウェブ化を実現しています。そのための準備として、上述の dxl2web というツールを使って、
・フォームの DXL(XML) から XSL を作る
・ノーツ文書の DXL(XML) を HTML 向けに微調整する
という処理を行います。この「微調整」の意味ですが、ノーツの機能を使って DXL エクスポートされた文書データのリッチテキストフィールドには HTML に近い(けど異なる)フォーマットでデータが格納されています。この似て非なるフォーマットを HTML で表示する前提となるフォーマットに変換する、という前処理を行っています。なお文書データをウェブ化、つまり HTML 化する XSLT の処理はこのフォーマットが微調整された文書 DXL に対して(表示時に)動的に行います。このためフォームの XSL を変更すれば、そのフォームを使う全文書の UI を変えるというカスタマイズを(後からでも)行うことができるような仕組みにしています。

理想は単独のツールだけで NSF をウェブ化できるのが理想と思いつつも、カスタマイズの要素を残そうとすると単独ツールで最後まで処理してしまうことは必ずしも正しくないと判断し、nsf2dxl2web は2回(カスタマイズ内容によってもう数回)のツール実行でウェブ化するような設計にしています。



(過去記事や続きはこちらです)
nsf2web2dxl の挑戦(2)



このページのトップヘ