Apache Xerces SAX2 検証パーサーを使用して、非常に単純な XML ファイルを解析および検証しようとしています。DTD は XML ファイルから参照され、単純なエンティティ リゾルバーは DTD ファイルの適切な InputStream を正常に返すことができます。私は非常に基本的なタグ構造を持っています。名前を付ける必要はないので、単純に XML タグに文字を付けます。主なタグは A です。A タグ内に 0 個以上の B が存在する可能性がありますが、B のみです。そして、B の中に 0 個以上の C があります。したがって、適切な XML は次のようになります。
<A>
<B><C>somecharacters</C></B>
</A>
単体テストを作成したところ、奇妙な動作が発生しました。上記と同様の XML をパーサーに渡して、一致する開始タグがなく、親要素 B がない C の終了タグのみを指定すると、パーサーは DTD 検証エラーを報告します。以下は、DTD に従って意図的に無効にした XML の例です。
<A>
<C>somecharacters</C></B>
</A>
この XML フラグメントが整形式でないことは明らかです。残念ながら (または、SAX パーサーで何かがわかりません)、パーサーは C タグに対して ContentHandler の startElement メソッドを呼び出し、その後、C タグ内の文字に対して characters メソッドを呼び出します。DTD は、A タグは B タグのみを子として持つことができ、C は最初に B 内にネストする必要があるため、C を持たないことを明確に述べています。私が理解していないのは、ネストされた C が適切な場所にないことに気付いた後、パーサーが文字メソッドを呼び出す理由です。
私の ContentHandler メソッドのアプリケーション ロジックは、タグが DTD に従ってネストされているという前提に依存しています。これら 3 つのメソッドに null チェッカーとエラー処理コードを入力したくありません。これは DTD バリデーターの仕事であると想定しているためです。
パーサーをセットアップするための私のコードは(例外処理部分は関係ありません):
private static final String VALIDATION_FEATURE = "http://xml.org/sax/features/validation";
private static final String SAX_PARSER_IMPLEMENTATION = "org.apache.xerces.parsers.SAXParser";
......
XMLReader parser = XMLReaderFactory.createXMLReader(SAX_PARSER_IMPLEMENTATION);
parser.setFeature(VALIDATION_FEATURE, true);
parser.setErrorHandler(new CustomErrorHandler());
parser.setEntityResolver(entityResolver);
parser.setContentHandler(handler);
InputSource inputSource = new InputSource(stream);
try {
parser.parse(inputSource);
} catch (IOException e) {
throw new ControlFileReadException("Error while parsing the control file.", e);
} catch (SAXException e) {
if (e.getCause() instanceof IncorrectCounterNameException) {
throw new IncorrectCounterNameException(e.getCause());
} else {
throw e;
}
}
private final class CustomErrorHandler implements ErrorHandler {
public void warning(SAXParseException spe) throws SAXException {
throw spe;
}
public void fatalError(SAXParseException spe) throws SAXException {
throw spe;
}
public void error(SAXParseException spe) throws SAXException {
throw spe;
}
}
どんな助けでも大歓迎です!