相比傳統 .properties/.ini,XML 提供層級結構、型別擴展、命名空間、驗證等優勢,已成 Java EE 標準(Tomcat server.xml, web.xml 等)。
| 特性 | SAX | DOM |
|---|---|---|
| 模式 | 事件驅動、流式讀取 | 樹模型、一次性載入記憶體 |
| 記憶體 | 極低(適合大檔) | 正比檔案大小 |
| 隨機存取 | 不支援 | 支援 |
| 適用場景 | 配置檔、大型資料交換 | 小檔、需頻繁修改樹結構 |
配置檔通常較小,但 SAX 代碼簡潔、效能穩定,本文採用 SAX(JDK 內建 javax.xml.parsers)。
myenv.xml<config>
<dbhost>localhost</dbhost>
<sqlname>mydb</sqlname>
<username>admin</username>
<password>secret</password>
</config>
放置於 WEB-INF/classes(Classpath 根路徑)。
DefaultHandlerpublic class ConfigParser extends DefaultHandler {
private Properties props = new Properties();
private String currentElement;
private StringBuffer currentValue = new StringBuffer();
@Override
public void startElement(String uri, String localName, String qName, Attributes attrs) {
currentElement = qName;
currentValue.setLength(0); // 重置緩衝
}
@Override
public void characters(char[] ch, int start, int length) {
currentValue.append(ch, start, length); // 累積文字內容
}
@Override
public void endElement(String uri, String localName, String qName) {
props.put(qName.toLowerCase(), currentValue.toString().trim());
}
public Properties getProps() { return props; }
}
public class XmlConfigLoader {
private Properties props;
public Properties getProps() { return props; }
public void parse(String filename) throws Exception {
ConfigParser handler = new ConfigParser();
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(false);
factory.setValidating(false); // 不驗證 DTD/Schema,加速
SAXParser parser = factory.newSAXParser();
// 從 Classpath 載入(適用 WAR/ JAR 內部資源)
URL url = getClass().getClassLoader().getResource(filename);
if (url == null) throw new FileNotFoundException("Config not found: " + filename);
parser.parse(url.toString(), handler);
this.props = handler.getProps();
}
}
public class App {
public static void main(String[] args) throws Exception {
XmlConfigLoader loader = new XmlConfigLoader();
loader.parse("myenv.xml");
Properties cfg = loader.getProps();
String host = cfg.getProperty("dbhost");
String user = cfg.getProperty("username");
String pwd = cfg.getProperty("password");
System.out.printf("連線資訊:%s / %s / ******%n", host, user);
}
}
endElement 中按元素名轉 Integer, Boolean 等。datasource.url),生成前綴鍵值。factory.setValidating(true) 搭配 XSD,確保配置合法。WatchService 監聽檔案變更,自動重新解析。characters() 可能多次調用分段傳回內容,必須用緩衝區累積(本文 StringBuffer 做法正確)。getResource("myenv.xml") 找 classpath 根;getResource("config/myenv.xml") 找子目錄。<?xml encoding="UTF-8"?>,Java 讀取預設 UTF-8。