旧字・旧仮名遣い変換ソフトウェア misima Servlet 版を公開した.同時に,JIS 第一・第二水準範囲内での旧字変換の問題(単純変換などを同時に指定したとき範囲外の漢字が混入してしまう問題)をやっと訂正した.こちらから利用できる.
辞書を先読みすることで高速化を図った misimaserver を,バックエンドで利用する.オプションを簡易化し,従来サーバで行っていた misima オプション引数の組立てをブラウザ側で実行する.Ajax を用いてページのリロードなしに変換結果を挿入する.従来のものと比べ,変換オプションが限られていてユーザ辞書も受け付けない欠点がある一方,高速に動作する.シンプルな画面で簡易に使いたいひとに向いている.処理可能なテキストサイズは 8,000 バイトの制限を設けた (Tomcat 5.5 server.xml の maxPostSize パラメータによる).
Ajax に基づくコード実装において,久しぶりに JavaScript と格闘した.先に紹介した O'Reilly の『Ajax & Java --- Java プログラマのための Ajax プライマー』が役立った.サーバを Perl で書くか,Java Servlet にするか悩んだのだけれど,本書の影響もあって後者を選択.
Ajax は JavaScript の一テクノロジーに過ぎないが,Google の地図アプリで俄然脚光を浴びるようになった.非同期にサーバと通信を行い,ページの一部を書き換えることで軽快な Web アプリを実現する.misima Servlet 版 JavaScript のコアな部分をあげておく.
<!-- Ajax misima フォーム -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>misima Servlet版</title>
<script language="JavaScript">
var req;
// misima 変換要求
function misimaconvert() {
var it = document.getElementById("obj").value;
var url = "/misimaservlet/convert";
// misima オプションパラメータの組立て
var ss = "<misima_param>" + parameter() + "</misima_param>"
+ it.replace(/\r?\n/g, ":#;~");
// HTTP リクエストの生成
if (window.XMLHttpRequest) {
req = new XMLHttpRequest();
}
else if (window.ActiveXObject) {
req = new ActiveXObject("Msxml2.XMLHTTP");
if (!req) {
req = new ActiveXObject("Microsoft.XMLHTTP");
}
}
// 変換要求 (非同期実行のポイント)
req.open("POST", url, true);
req.setRequestHeader("content-type",
"application/x-www-form-urlencoded; charset=UTF-8");
req.onreadystatechange = callback;
req.send("obj=" + encodeURI(ss));
}
// misima パラメータ組立て
function parameter() {
var params = "-q";
switch (document.getElementById("bopt").selectedIndex) {
case 0: params = params + " -kyit -s"; break;
case 1: params = params + " -kyt -s"; break;
case 2: params = params + " -kt -s"; break;
case 3: params = params + " -t -s"; break;
default: break;
}
if (document.getElementById("jopt").checked) {
params = params + " j";
} else {
params = params + " c";
}
if (document.getElementById("topt").checked) {
params = params + " -x kuit -g";
}
if (document.getElementById("nopt").checked) {
params = params + " -n";
}
return params;
}
// Ajax コールバック: 非同期に受信した変換結果をページに挿入する.
function callback() {
if (req.readyState == 4) {
if (req.status == 200) {
var res = req.responseText.replace(/:#;~/g, "<br />");
document.getElementById("out").innerHTML = res;
}
}
}
</script>
</head>
<body>
オプション<br />
<select id="bopt">
<option value="1" selected>旧字/旧仮名/用語/繰返</option>
<option value="2">旧字/旧仮名/用語</option>
<option value="3">旧字/旧仮名</option>
<option value="4">旧字</option>
</select>
<input type="checkbox" id="topt" />LaTeX
<input type="checkbox" id="jopt" />第一・二水準内
<input type="checkbox" id="nopt" />仮名反転<br />
テキスト入力<br />
<input type="button" value="変 換"
onclick="focusIn();misimaconvert();" /><br />
<textarea id="obj" cols="40" rows="6"></textarea>
変換結果<br />
<div id="out" />
</body>
</html>
HTTP リクエストオブジェクトを生成し,misima パラメータ+対象テキストを POST リクエストで送信し,一方コールバックで非同期に結果を待ち受けるところがポイントである (req.open から req.send まで).オプションパラメータの組立ての関数 (parameter()) において,getElementById() メソッドでないと select や checkbox のオブジェクトが参照できないのは何故? 「document.フォーム名.エレメント名」ではダメなんである.ここが悩んだところである.
このフォームから起動される Java Servlet は次のとおりである.socket を使って misimaserver と通信する以外はまったく普通のサーブレットである.出力テキストは UTF-8 なので,setContentType メソッドの引数に charset=UTF-8 を入れておかないと,getWriter().write() が正しく動作しない.
// misima servlet for misimaserver & Ajax client
// 2007 (c) isao yasuda, All Rights Reserved.
import java.io.*;
import java.net.*;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class misimaServlet extends HttpServlet {
private static String HOST = "localhost";
private static int PORT = 34000;
private Socket sock;
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException
{
/** ユーザリクエストの取得 */
String obj = (String) req.getParameter("obj");
StringBuffer rbuf = new StringBuffer();
String ct = "?";
if (obj != null) {
/** misimaserver ソケット接続 */
try {
sock = new Socket(HOST, PORT);
/** 対象テキストを送信する */
Writer send = new OutputStreamWriter(
sock.getOutputStream(), "UTF-8");
send.write(obj + "\n");
send.flush();
/** 変換結果テキストを受信する */
InputStreamReader recv = new InputStreamReader(
new BufferedInputStream(sock.getInputStream()), "UTF-8");
int c;
while ((c = recv.read()) != -1) {
rbuf.append((char)c);
}
}
catch (Exception e) {
rbuf.append("** Error occured in connection.\n" + obj);
}
finally {
if (sock != null) sock.close();
sock = null;
}
ct = rbuf.toString();
}
/** 結果出力 */
res.setContentType("text/xml; charset=UTF-8");
res.setHeader("Cache-Control", "no-cache");
res.getWriter().write(ct);
}
}

Comments