Eclipseプラグイン実践テクニック(4)
ビルド機能を応用してXML検証機能を作る
NTTデータ先端技術 竹添直樹
NTTデータ 基盤システム事業本部 岡本隆史
2006/12/9
 |
ビルダの機能を応用してSAXパースする |
続いて、XMLファイルのバリデーションを行うビルダに移ります。ビルダを定義するには拡張ポイントorg.eclipse.core.resources.buildersを使用します。また、このビルダはすでに作成したXMLNatureと関連付けますので、ネイチャの定義にビルダとの関連付けを追加します。plugin.xmlは以下のようになります(追加部分を赤字にしてあります)。
| リスト4 ビルダの定義 |
<extension
id="XMLBuilder"
name="XMLビルダ"
point="org.eclipse.core.resources.builders">
<builder
hasNature="true">
<run
class="jp.sf.amateras.builder.XMLBuilder"> ... (1)
</run>
</builder>
</extension>
<extension
id="sampleNature"
name="XMLネイチャ"
point="org.eclipse.core.resources.natures">
<runtime>
<run
class="jp.sf.amateras.builder.XMLNature">
</run>
</runtime>
<builder
id="jp.sf.amateras.builder.XMLBuilder">
</builder>
</extension> |
(1)で指定されているXMLBuilderがビルド処理を行うクラスです。このクラスはorg.eclipse.core.resources.IncrementalProjectBuilderクラスを継承して実装します。
| リスト5 XMLBuilder |
public class XMLBuilder extends IncrementalProjectBuilder {
public static final String BUILDER_ID = "jp.sf.amateras.builder.XMLBuilder";
protected IProject[] build(int kind, Map args, IProgressMonitor monitor) // … (1)
throws CoreException {
if (kind == FULL_BUILD) {
fullBuild(monitor);
} else {
IResourceDelta delta = getDelta(getProject());
if (delta == null) {
fullBuild(monitor);
} else {
incrementalBuild(delta, monitor);
}
}
return null;
}
/** フルビルド */
private void fullBuild(
IProgressMonitor monitor){ // … (2)
try {
getProject().accept(new XMLResourceVisitor());
} catch (CoreException e) {
e.printStackTrace();
}
}
/** インクリメンタル・ビルド */
private void incrementalBuild(IResourceDelta delta, IProgressMonitor monitor){ // … (3)
try {
delta.accept(new XMLDeltaVisitor());
} catch (CoreException e) {
e.printStackTrace();
}
}
} |
ビルドを行う場合、(1)のbuild()メソッドが呼び出されます。ビルドは場合によって、プロジェクト全体のビルドを行うフルビルドと、変更されたファイルのみビルドを行うインクリメンタル・ビルドに分かれます。上記の例では、フルビルドの場合は(2)のfullBuild()メソッド、インクリメンタル・ビルドの場合は(3)のincrementalBuild()メソッドを呼び出しています。
■フルビルドの場合はリソースビジタ
フルビルドの場合は、プロジェクト内のすべてのファイルを処理する必要があります。そこで、リソースビジタを使用してプロジェクト内のすべてのリソースをツリーウォークします。リソースビジタはorg.eclipse.core.resources.IResourceVisitorインターフェイスを実装して作成します。実装しなければならないのはvisit()メソッドだけです。
| リスト6 XMLResourceVisitor |
public class XMLResourceVisitor implements IResourceVisitor {
public boolean visit(IResource resource)
throws CoreException {
XMLValidator.doValidate(resource);
return true;
}
} |
XMLValidator#doValidate()でXMLのバリデーションを行っています。バリデーション処理の実装については、後述します。
■インクリメンタル・ビルドの場合はリソースデルタ
インクリメンタル・ビルドの場合は、変更の
| リスト7 XMLDeltaVisitor |
public class XMLDeltaVisitor implements IResourceDeltaVisitor {
public boolean visit(IResourceDelta delta)
throws CoreException {
IResource resource = delta.getResource();
int kind = delta.getKind();
if(kind == IResourceDelta.ADDED
|| kind == IResourceDelta.CHANGED){
XMLValidator.doValidate(resource);
}
return true;
}
} |
差分を格納したリソースデルタ(IResourceDelta)をツリーウォークします。この場合、ビジタクラスはorg.eclipse.core.resources.IResourceDeltaVisitorインターフェイスを実装します。
リソースデルタには、プロジェクト内のどのリソースが追加、変更、削除されたのかがツリー状に格納されています。ここでは、追加もしくは変更されたリソースに対してXMLバリデーションを行っています。
■バリデーションとリソース・マーカ
さて、肝心のXMLのバリデーション処理ですが、SAXパーサのエラーハンドラで行うことにします。エラーハンドラは、エラーが発生した際にバリデーション対象のファイルに対してリソース・マーカを付与するよう実装します。リソース・マーカはエディタ左端のルーラや問題ビューなどに表示されます。
編集部注:SAXパーサについて詳しく知りたい読者は、@IT XML&SOA フォーラムの、「SAXによるシンプルなXML文書の操作」や「XMLプログラミングのためのAPI」を参照してください。
 |
| 図1 リソース・マーカ |
バリデーション処理の実装は以下のとおりです。
| リスト8 XMLValidator |
public class XMLValidator {
private static final String MARKER_TYPE = "jp.sf.amateras.builder.XMLProblem";
private static SAXParserFactory factory = SAXParserFactory.newInstance();
/** バリデーション処理 */
public static void doValidate(IResource resource){
// XMLファイルだったらバリデーションを行う
if(resource instanceof IFile
&& resource.getName().endsWith(".xml")){
IFile file = (IFile) resource;
try {
// まずマーカをすべて削除する
file.deleteMarkers(IMarker.PROBLEM, false, IResource.DEPTH_ZERO);
// エラーハンドラをセットしてパースを行う
XMLErrorHandler reporter =
new XMLErrorHandler(file);
SAXParser parser = factory.newSAXParser();
parser.parse(file.getContents(), reporter);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
/** SAXパーサに設定するエラーハンドラ */
private static class XMLErrorHandler
extends DefaultHandler {
private IFile file;
public XMLErrorHandler(IFile file) {
this.file = file;
}
private void addMarker(SAXParseException e
, int severity) { // … (1)
// マーカを作成
String message = e.getMessage();
int lineNumber = e.getLineNumber();
try {
IMarker marker =
file.createMarker(IMarker.PROBLEM);
marker.setAttribute(IMarker.MESSAGE, message);
marker.setAttribute(IMarker.SEVERITY
, severity);
if (lineNumber == -1) {
lineNumber = 1;
}
marker.setAttribute(IMarker.LINE_NUMBER
, lineNumber);
} catch (CoreException ex) {
ex.printStackTrace();
}
}
public void error(SAXParseException exception)
throws SAXException {
addMarker(exception, IMarker.SEVERITY_ERROR);
}
public void fatalError(SAXParseException exception)
throws SAXException {
addMarker(exception, IMarker.SEVERITY_ERROR);
}
public void warning(SAXParseException exception)
throws SAXException {
addMarker(exception, IMarker.SEVERITY_WARNING);
}
}
} |
SAXパーサのエラーハンドラでエラーを捕捉すると、(1)のaddMarker()メソッドでリソース・マーカを作成するようになっています。処理自体は普通にSAXパースしているだけですので、特に難しい部分はないでしょう。
|
2/3 |
 |
| INDEX |
| 第4回 ビルド機能を応用してXML検証機能を作る |
| |
Page1
XMLのバリデーションを行うビルダの実装
ネイチャについて |
 |
Page2
ビルダの機能を応用してSAXパースする |
| |
Page3
ネイチャをプロジェクトに追加する
Eclipseの持つ機能を実践的に利用する |