為什麼選擇 XML Schema (XSD) 而非 DTD?
| 特性 | DTD | XML Schema (XSD) |
| 語法 | 非 XML (獨立語法) | **XML 本身** (易讀、可用 XML 工具處理) |
| 資料類型 | 極少 (PCDATA, ID, IDREF...) | **豐富內建類型** (string, integer, decimal, date, boolean, QName...),支援自定義派生類型 |
| 命名空間 | 不支援 | **原生支援** (targetNamespace, xmlns) |
| 擴充性 | 困難 | include/import/redefine 機制完善 |
| 約束能力 | 基本結構 | 唯一性 (unique/key/keyref)、值範圍、長度、模式 (regex)、預設/固定值 |
| 標準地位 | 早期標準 | **W3C 推薦標準 (2001/05/02)**,現代 XML 應用首選 |
實戰範例:Grapevine 配置驗證
1. XML 實例 (grapevine.xml)
<?xml version="1.0" encoding="UTF-8"?>
<GRAPEVINE xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="grapevine.xsd">
<GRAPE class="test.TestAbc" id="resourceTestAbc"/>
<GRAPE class="java.lang.String" id="stringName" value="ok..."/>
</GRAPEVINE>
2. XSD 結構定義 (grapevine.xsd)
<?xml version="1.0" encoding="ISO-8859-1"?>
<xs:schema xmlns:xs="https://www.w3.org/2001/XMLSchema">
<!-- 根元素 GRAPEVINE -->
<xs:element name="GRAPEVINE">
<xs:complexType>
<xs:sequence>
<!-- GRAPE 子元素,可出現 0 次到無限次 -->
<xs:element name="GRAPE" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="id" type="xs:string" use="required"/>
<xs:attribute name="class" type="xs:string" use="required"/>
<xs:attribute name="value" type="xs:string" use="optional"/>
</xs:complexType>
</xs:element>
</xs:sequence>
<!-- 唯一性約束:所有 GRAPE 的 id 屬性必須唯一 -->
<xs:unique name="idUnique">
<xs:selector xpath=".//GRAPE"/>
<xs:field xpath="@id"/>
</xs:unique>
</xs:complexType>
</xs:element>
</xs:schema>
關鍵 XSD 元素解析
xs:schema:根元素,宣告命名空間 xmlns:xs="https://www.w3.org/2001/XMLSchema"。
xs:element:定義元素,name 對應 XML 標籤名。
xs:complexType:包含屬性或子元素的複雜類型。
xs:sequence:子元素**按順序**出現 (還有 choice, all)。
minOccurs/maxOccurs:出現次數限制,unbounded 表無上限。
xs:attribute:定義屬性,use="required" 必填,optional 選填。
xs:unique/key/keyref:身分識別約束,配合 selector (範圍) + field (值路徑)。
Java 程式化驗證 (JDK 內建 JAXP API)
import javax.xml.XMLConstants;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.*;
import java.io.File;
import java.io.IOException;
public class XsdValidator {
public static void main(String[] args) {
String xsdPath = "grapevine.xsd";
String xmlPath = "grapevine.xml";
try {
// 1. 建立 SchemaFactory (W3C XML Schema 語言)
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
// 2. 編譯 Schema
Schema schema = factory.newSchema(new File(xsdPath));
// 3. 建立 Validator
Validator validator = schema.newValidator();
// 4. 驗證 (拋出 SAXException 表示失敗)
validator.validate(new StreamSource(new File(xmlPath)));
System.out.println("✅ XML 驗證通過");
} catch (SAXException e) {
System.err.println("❌ XML 驗證失敗: " + e.getMessage());
} catch (IOException e) {
System.err.println("❌ IO 錯誤: " + e.getMessage());
}
}
}
進階技巧與最佳實踐
- 命名空間驗證:XML 宣告
xmlns="...",XSD 設 targetNamespace,Java 驗證時需處理命名空間感知的 SchemaFactory。
- 錯誤收集而非拋出:實作
ErrorHandler 介面,將所有錯誤/警告收集到列表,一次性報告,避免首錯即停。
validator.setErrorHandler(new CollectingErrorHandler());
- 效能優化:
Schema 物件**執行緒安全且可重用**,應快取重用,避免重複編譯 XSD。
- 大檔案流式驗證:配合
StAX (XMLStreamReader) 或 SAX 事件驅動驗證,避免載入整個 DOM 到記憶體。
validator.validate(new StAXSource(xmlStreamReader));
- XSD 1.1 (JDK 9+ 支援):支援
xs:assert、xs:alternative 條件型別、xs:openContent 擴充性。
SchemaFactory.newInstance("https://www.w3.org/XML/XMLSchema/v1.1")
常見錯誤與排查
| 錯誤現象 | 可能原因 | 解決方向 |
| 找不到元素/屬性聲明 | 命名空間不匹配 (XML 有 xmlns,XSD 無 targetNamespace 或反之) | 統一命名空間策略:XSD 設 targetNamespace,XML 同樣宣告並用 xsi:schemaLocation 指定 |
| 類型轉換失敗 | XML 值不符合 XSD 類型限制 (如 integer 欄位填 "abc") | 檢查資料產生端;XSD 用 pattern 限制格式 |
| unique/key 違反 | 重複 id/key 值 | 檢查資料唯一性邏輯;XPath selector/field 路徑正確性 |
| 驗證極慢 / OOM | 大 XML 載入 DOM 驗證 | 改用 StAX/SAX 流式驗證 |
總結
XML Schema 提供強大、標準化、可擴充的 XML 結構與資料約束能力。Java JAXP API (javax.xml.validation) 提供零依賴的標準驗證實作。掌握 XSD 核心元素、命名空間處理、唯一性約束、錯誤收集器模式、流式驗證與 Schema 快取重用,即能在企業級應用中建立健壯的 XML 資料驗證防線。