SAXで困る

Kijimunaのリファクタリング対応を行うために、diconファイルをSAXパースする処理を少し変更した。たとえば以下のようなdiconがあった場合、

<components>
  <component name="hoge"
     class="example.ClientImpl">
  ...

name属性、class属性の値に加え、それらの属性が定義されているオフセット値と長さを取得して、オブジェクトモデルに持たせるように修正した。ここでオフセット値とはファイルの先頭から属性定義箇所までのバイト数のこと。上の例だと"name=..","class=.."の開始位置が該当する。このオフセット値と長さの値を用いて、リファクタリングによる変更の範囲を指定する、という流れ。泥臭い処理方式ではあるが、plugin.xmlエディターでも同じような処理をしていたので、一応正しい実装方法なんだろう。

しかしオフセット値を取得する際に困ったことが発生。SAXのLocatorは位置情報としては、要素の定義行と行頭からのバイト数しか返してくれない。上記例の場合だと、要素の位置情報として"3行目,30文字目"という情報しか取得できない(ちなみに3行目、というのはelementタグの閉じタグ行)。これだけの情報から、目的の属性値のオフセット値を取得しないといけない。仕方ないので、3行目の閉じタグに対応する開きタグを探して、その範囲の文字列をタグ文字列として取得し、そこから目的の属性のオフセットと長さを求めて、それをファイル全体におけるタグ開始位置までのオフセットに加えて、、ということをする羽目に。

plugin.xmlエディターでもXMLの解析にはSAXを使っており、上のような泥臭い処理をしていた。げげげ。
もっとエレガントな方法はないのかな〜。DOMなら楽?

その点、JDTのASTモデルではオフセット値がパース時にセットされてるので、このあたりの処理も簡単だったな。ソースコードをパーシングしてごにょごにょやるプログラムを作るときは、はじめのパーシングで取得できる情報はできるだけ多く取得せよ、ということかな。