えー、久々にお仕事ネタです。(たまには書かないと・・・)
Javaで、XMLのエスケープ処理とかの実装を調査する機会がありまして、ちょっとハマったので、覚書としてメモしておきます。
XML文書をパースする際には、定義済み実体参照を置換すること(例えば、<を<にするとか)は理解していたんですが、文字参照(&#で始まる10進や、&#xで始まる16進)を文字に置換するというのを忘れておりまして。
そこで、16進数字から文字へ変換する処理を実装しようと、APIを探したんですが、コレ!というのが見当たりません。ググってもなかなかヒットしない。逆(文字から16進数字)は、Integer#toHexStringでできるんですが・・・。
じゃ自作するか、と同僚とアレコレやってみました。intにしてbyte配列にしてビット演算して・・・と試行錯誤して何とか出来たは出来たんですが、イマイチすっきりしなくて。
ダメ元で、もう一度キーワードを変えてググったら・・・やっとよさげなのにヒットしました。
decodeメソッドだけ抜粋。
// NCRデコードを行う(10進、16進) public static String decode(String str) { Pattern pattern = Pattern.compile("&#(\\d+);|&#([\\da-fA-F]+);"); Matcher matcher = pattern.matcher(str); StringBuffer sb = new StringBuffer(); Character buf; while(matcher.find()){ if(matcher.group(1) != null){ buf = new Character( (char)Integer.parseInt(matcher.group(1))); }else{ buf = new Character( (char)Integer.parseInt(matcher.group(2), 16)); } matcher.appendReplacement(sb, buf.toString()); } matcher.appendTail(sb); return sb.toString(); }
なるほど。Integer#parseIntした値をcharでキャストしてCharacterに食わせればいいのか・・・うーん、こんなに簡単だったとは・・・。
しかも、「&#x○○○○;」を抽出する正規表現のロジックも載ってるし。Matcherってこうやって使うのね。appendReplacementか・・・勉強になります。
以上、覚書でした。
なんか、今どきXMLパース処理なんて、”車輪の再発明”しているような気がしないでもないですが、XML1.0勧告をちゃんと読むいい機会になりました。
apache の commons-lang3 にあるようです。
http://commons.apache.org/lang/api-release/org/apache/commons/lang3/StringEscapeUtils.html#unescapeHtml4(java.lang.String)