HTMLWriterは、 HTML出力を実際に行うクラス。
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なので使えない!
この変数を無視すると、タグを表す「<」が軒並み「<」に変更されてしまったり属性が変になってしまったりして、うまくない。
次に、格好も効率も悪いけれど、「&#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>コード文字列が分割して呼ばれても、必ず先頭は&#で、末尾が;で来るのが前提</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();
}
}