org.dom4j.DocumentException: Error on line 1 of document: 前言中不允許有內容。
Nested exception: 前言中不允許有內容。
at org.dom4j.io.SAXReader.read(SAXReader.java:482)
at com.core.util.XmlTemplateUtil.loadXmlTemplateByIO(XmlTemplateUtil.java:93)
...
乍看之下,XML 檔案開頭並無多餘字元,為何解析器仍報「前言中不允許有內容」?
BOM 是位於檔案最開頭的 2~4 個位元組,用於標示編碼與位元組序:
FE FFFF FEEF BB BF(三個位元組)XML 規範要求文件必須以 <?xml ...?> 宣告開頭,不允許任何前導位元組。許多編輯器(如 Windows 記事本)另存為 UTF-8 時預設會加入 BOM,導致解析器在讀取第一個字元時遇到 0xEF 而非 <,拋出上述異常。
EF BB BF。head -c 3 your.xml | xxd,輸出若為 ef bb bf 即確認有 BOM。| 編輯器 | 操作步驟 |
|---|---|
| Notepad++ | 選單 編碼(E) → 轉為 UTF-8 (無 BOM) → 存檔 |
| UltraEdit | 檔案(F) → 轉換(C) → UTF-8 無 BOM |
| VS Code | 右下角編碼欄位點擊 → 以編碼儲存(Save with Encoding) → 選 UTF-8 (without BOM) |
| IntelliJ IDEA | File → File Encoding → UTF-8(預設不寫 BOM) |
| Linux 指令 | sed -i '1s/^\xEF\xBB\xBF//' your.xml 移除首行 BOM |
「改成 ANSI 編碼就好了」
ANSI(實際上是系統預設代碼頁,如 GBK/Big5)確實沒有 BOM,但無法支援多國語言字元。正確做法是保留 UTF-8 編碼,移除 BOM,兼顧相容性與國際化。
若無法控制上游檔案來源,可在讀取前預處理:
public static InputStream removeBom(InputStream in) throws IOException {
PushbackInputStream pb = new PushbackInputStream(in, 3);
byte[] bom = new byte[3];
pb.read(bom);
if (!(bom[0] == (byte)0xEF && bom[1] == (byte)0xBB && bom[2] == (byte)0xBF)) {
pb.unread(bom); // 非 BOM,退回
}
return pb;
}
「前言中不允許有內容」九成以上是 UTF-8 BOM 惹的禍。養成「儲存為 UTF-8 無 BOM」的習慣,或在 CI 流程加入 BOM 檢查,即可徹底杜絕此類問題。