S-JIS[2007-02-04] 変更履歴

HTMLWriter(Swing)

HTMLWriterは、 HTML出力を実際に行うクラス。


独自HTMLWriterの雛形

public class HteWriter extends HTMLWriter {

	public HteWriter(Writer w, Document doc, int pos, int len) {
		super(w, (HTMLDocument) doc, pos, len);
	}
}

インデントをタブに変更する例

HTMLWriterのデフォルトは、スペース埋めになっている。自分はタブの方が好きなので、タブに変更する。

public class HteWriter extends HTMLWriter {
〜
	/**
	 * インデントの実体を保持するバッファ
	 * <p>タブ'\t'で埋めておき、必要な長さだけ出力する</p>
	 */
	private char[] indentChars = { '\t', '\t', '\t', '\t', '\t', '\t', '\t', '\t' };

	protected void indent() throws IOException {
		if (!isLineEmpty()) return;

		int indent = getIndentLevel();
		if (indent > indentChars.length) {
			indentChars = new char[indent + 8];
			Arrays.fill(indentChars, '\t');
		}
		output(indentChars, 0, indent);
	}
}

日本語を出力する例

HTMLWriterのデフォルトでは、ASCII文字(コード0〜127)以外の文字は、コード表記(&#nnnnn;)で出力される!このクラスの製作者、外国のこと全然考えてないだろ!

コード出力する部分はHTMLWriter#output()のswitch文のdefault:内に直接記述されているので、そこだけ直すというわけに行かない。
仕方が無いのでoutput()をオーバーライドして内容をそっくりコピーしてdefaultだけ直そうと思ったら、output()の先頭にあるreplaceEntitiesという変数がprivateなので使えない!
この変数を無視すると、タグを表す「<」が軒並み「&lt;」に変更されてしまったり属性が変になってしまったりして、うまくない。

次に、格好も効率も悪いけれど、「&#nnnnn;」という文字列が出力されたらコードに戻してやることを考えた。
default内でコード出力しているoutput(String)を改造すればいいかと思ったら、こいつもprivateメソッドだ!(つまり継承クラスに同じシグニチャーでメソッドを作っても、オーバーライドされるわけではないので呼ばれない)
仕方がないので、さらにその先であるWriter#write()でその処理を行うことにした。

これで目的は達成できたけど、明らかに変なプログラムなので気持ち悪い…。

public class HteWriter extends HTMLWriter {

	public HteWriter(Writer w, Document doc, int pos, int len) {
		super(new CodeWriter(w), (HTMLDocument) doc, pos, len);
	}
}
class CodeWriter extends Writer {

	protected Writer w;

	public CodeWriter(Writer w) {
		this.w = w;
	}

	/**
	 * バッファに保存中かどうか
	 */
	private boolean code;

	/**
	 * コード文字列を保持する為のバッファ
	 */
	private StringBuffer sb = new StringBuffer();

	private char[] c = new char[1];

	/**
	 * <p>コード文字列が分割して呼ばれても、必ず先頭は&amp;#で、末尾が;で来るのが前提</p>
	 */
	public void write(char[] cbuf, int off, int len) throws IOException {
		if (len >= 2 && cbuf[off] == '&' && cbuf[off + 1] == '#') {
			sb.setLength(0); //バッファをクリア
			code = true;
		}
		if (code) {
			sb.append(cbuf, off, len);
			len = sb.length();
			if (sb.charAt(len - 1) != ';') return;

			String str = sb.substring(2, len - 1);
			cbuf = c;
			cbuf[off = 0] = (char) Integer.parseInt(str);
			len = 1;
			code = false;
		}

		w.write(cbuf, off, len);
	}

	public void flush() throws IOException {
		w.flush();
	}

	public void close() throws IOException {
		w.close();
	}
}

Swing目次へ戻る / Java目次へ戻る
メールの送信先:ひしだま