結論
外部エンティティを含むxmlファイルを読み込む際、FileNotFoundExceptionが発生する場合はsystemIdにXMLファイルのパスを設定すると問題が解消します。
詳細
employees.xmlは従業員情報を記録したファイルです。このemployees.xmlは外部エンティティとしてemployee1.xmlとemployee2.xmlを参照しています。
employees.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE employees [
<!ENTITY employee1 SYSTEM "./employee1.xml">
<!ENTITY employee2 SYSTEM "./employee2.xml">
]>
<employees>
<employee>
<name>山田</name>
<role>社長</role>
</employee>
&employee1;
&employee2;
</employees>
employee1.xml
<employee>
<name>鈴木</name>
<role>営業</role>
</employee>
employee2.xml
<employee>
<name>佐藤</name>
<role>経理</role>
</employee>
<employee>
<name>田中</name>
<role>人事</role>
</employee>
このemployees.xmlを読み込むことを考えて、以下のようなコードを作成&実行したところjava.io.FileNotFoundExceptionが発生しました。
String xmlFile = "D:\\tmp\\employees.xml";
try (InputStream inputStream = Files.newInputStream(Paths.get(xmlFile))) {
Document document = DocumentBuilderFactory.newInstance()
.newDocumentBuilder()
.parse(inputStream);
// Do Something
} catch (IOException | ParserConfigurationException | SAXException e) {
e.printStackTrace();
}
これはemployees.xmlの中にある外部エンティティの相対パスがうまく解決できていないことが原因です。そこで、この相対パスを解決するためのベースであるsystemIdにemployees.xmlのパスを設定します。ここではDocumentBuilderクラスのparseメソッドの引数としてsystemIdにemployees.xmlのパスを設定したところ、java.io.FileNotFoundExceptionは発生せず、想定通りにxmlファイルの読み込みができました。
String xmlFile = "D:\\tmp\\employees.xml";
try (InputStream inputStream = Files.newInputStream(Paths.get(xmlFile))) {
Document document = DocumentBuilderFactory.newInstance()
.newDocumentBuilder()
.parse(inputStream, xmlFile); // ★
// Do Something
} catch (IOException | ParserConfigurationException | SAXException e) {
e.printStackTrace();
}
環境
D:\>java -version
openjdk version "17.0.3" 2022-04-19
OpenJDK Runtime Environment Temurin-17.0.3+7 (build 17.0.3+7)
OpenJDK 64-Bit Server VM Temurin-17.0.3+7 (build 17.0.3+7, mixed mode, sharing)
D:\>javac -version
javac 17.0.3