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(); } }