XML 作為數據交換的標準格式,在企業級應用中廣泛使用。Java 提供了四種主流 XML 解析技術:DOM、SAX、StAX、JAXB,各有優劣,適用場景不同。本文將深度解析四大方案的原理、特性、代碼實戰及選型建議,幫助開發者根據業務需求做出最佳技術決策。
| 技術 | 解析模式 | 內存佔用 | 性能 | 適用場景 | 學習曲線 | 特點 |
|---|---|---|---|---|---|---|
| DOM | 樹模型(一次性加載全文檔) | 高(與文檔大小成正比) | 較慢 | 小文檔、需隨機訪問/修改結構 | 低 | 類似 .NET XmlDocument,API 直觀 |
| SAX | 事件驅動流式解析 | 極低(不載入文檔樹) | 快 | 大文檔、只讀、順序處理 | 中 | 回調式編程,狀態管理複雜 |
| StAX | 拉取式流式解析 | 極低 | 快 | 大文檔、需控制解析流程 | 中 | 類似 .NET XmlReader,主動拉取事件 |
| JAXB | 對象綁定(ORM 風格) | 中等(生成對象樹) | 中等 | 業務對象映射、配置文件、WebService | 低(註解驅動) | 標準規範,註解配置,開發效率最高 |
SAX 通過繼承 DefaultHandler 重寫回調方法實現解析邏輯,適合大文件順序讀取:
public class ConfigParser extends DefaultHandler {
private String currentConfigSection;
public SysConfigItem sysConfig;
public List<InterfaceConfigItem> interfaceConfigList = new ArrayList<>();
public List<FtpConfigItem> ftpConfigList = new ArrayList<>();
public List<AdapterConfigItem> adapterConfigList = new ArrayList<>();
@Override
public void startDocument() throws SAXException {
// 初始化容器
sysConfig = new SysConfigItem();
interfaceConfigList = new ArrayList<>();
ftpConfigList = new ArrayList<>();
adapterConfigList = new ArrayList<>();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if ("Item".equalsIgnoreCase(qName) && attributes.getLength() > 0) {
// 根據當前 section 分發屬性到對應對象
switch (currentConfigSection) {
case "SysConfigItem":
sysConfig = new SysConfigItem(attributes);
break;
case "InterfaceConfigItems":
interfaceConfigList.add(new InterfaceConfigItem(attributes));
break;
case "FtpConfigItems":
ftpConfigList.add(new FtpConfigItem(attributes));
break;
case "AdapterConfigItems":
adapterConfigList.add(new AdapterConfigItem(attributes));
break;
}
} else {
currentConfigSection = qName; // 記錄當前元素層級
}
}
// endElement、characters 可按需重寫
}
public class ConfigItemBase {
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public ConfigItemBase(Attributes attributes) {
Class<?> cls = this.getClass();
Field[] fields = cls.getDeclaredFields();
for (Field field : fields) {
String fieldName = field.getName();
String fieldType = field.getType().getSimpleName();
for (int i = 0; i < attributes.getLength(); i++) {
if (attributes.getQName(i).equalsIgnoreCase(fieldName)) {
field.setAccessible(true);
try {
String value = attributes.getValue(i);
if ("String".equalsIgnoreCase(fieldType)) {
field.set(this, value);
} else if ("Integer".equalsIgnoreCase(fieldType)) {
field.set(this, Integer.valueOf(value));
} else if ("Double".equalsIgnoreCase(fieldType)) {
field.set(this, Double.valueOf(value));
} else if ("Date".equalsIgnoreCase(fieldType)) {
field.set(this, DATE_FORMAT.parse(value));
} else {
System.out.println("Warning: Unhandled field type " + fieldType);
}
} catch (Exception e) {
e.printStackTrace();
}
break;
}
}
}
}
}
優點:內存效率極高、流式處理大文件無壓力。
缺點:編程模式反直覺、需手動維護解析狀態、無法隨機訪問、修改 XML 困難。
JAXB (Java Architecture for XML Binding) 將 XML 直接映射為 Java 對象,通過註解定義映射規則,開發效率最高,適合大多數業務場景。
@XmlRootElement(name = "batchSyncOrderRelationReq")
@XmlAccessorType(XmlAccessType.FIELD) // 基於字段綁定,忽略 getter/setter
public class BatchSyncOrderRelationReq extends BossMessage<BatchSyncOrderRelationReq> {
@XmlElement(name = "msgTransactionID")
private String msgTransactionId = "";
@XmlElement(name = "reqNum")
private String reqNum = "";
@XmlElement(name = "reqBody")
private List<BatchSyncOrderRelationReqBody> reqBodyList;
// getter/setter 省略...
@Override
public BatchSyncOrderRelationReq Deserialized(String interBossXmlContent) throws BusinessException {
try {
// 1. 解析外層 MessageHead
JAXBContext headContext = JAXBContext.newInstance(MessageHead.class);
Unmarshaller headUnmarshaller = headContext.createUnmarshaller();
MessageHead head = (MessageHead) headUnmarshaller.unmarshal(new StringReader(interBossXmlContent));
// 2. 解析內層 CDATA 業務報文
JAXBContext bodyContext = JAXBContext.newInstance(BatchSyncOrderRelationReq.class);
Unmarshaller bodyUnmarshaller = bodyContext.createUnmarshaller();
BatchSyncOrderRelationReq req = (BatchSyncOrderRelationReq) bodyUnmarshaller.unmarshal(
new StringReader(head.getSvcCont().trim())
);
req.setHead(head);
return req;
} catch (JAXBException e) {
throw new BusinessException("反序列化失敗", e);
}
}
}
@XmlAccessorType(XmlAccessType.FIELD)
public class BatchSyncOrderRelationReqBody {
@XmlElement(name = "oprNumb")
private String oprNumb = "";
@XmlElement(name = "subscriptionInfo")
private SubscriptionInfo subscriptionInfo;
// getter/setter 省略...
}
@XmlAccessorType(XmlAccessType.FIELD)
public class SubscriptionInfo {
@XmlElement(name = "oprTime") private String oprTime = "";
@XmlElement(name = "actionID") private String actionId = "";
@XmlElement(name = "brand") private String brand = "";
@XmlElement(name = "effTime") private String effTime = "";
@XmlElement(name = "expireTime") private String expireTime = "";
@XmlElement(name = "feeUser_ID") private String feeUserId = "";
@XmlElement(name = "destUser_ID") private String destUserId = "";
@XmlElement(name = "actionReasonID") private String actionReasonId = "";
@XmlElement(name = "servType") private String servType = "";
@XmlElement(name = "subServType") private String subServType = "";
@XmlElement(name = "SPID") private String spId = "";
@XmlElement(name = "SPServID") private String spServId = "";
@XmlElement(name = "accessMode") private String accessMode = "";
@XmlElement(name = "feeType") private String feeType = "";
// getter/setter 省略...
}
報文中 <SvcCont><![CDATA[ <?xml ...> ... ]]></SvcCont> 包含嵌套 XML,解決方案:
MessageHead 獲取 SvcCont 文本內容new StringReader(xmlString) 作為 Unmarshaller 輸入| 註解 | 作用域 | 說明 |
|---|---|---|
| @XmlRootElement | 類 | 標識根元素,可指定 name |
| @XmlAccessorType | 類 | FIELD(字段)/PROPERTY(屬性)/NONE/PUBLIC_MEMBER |
| @XmlElement | 字段/方法 | 映射為 XML 元素,可指定 name、required、namespace |
| @XmlAttribute | 字段/方法 | 映射為 XML 屬性 |
| @XmlElementWrapper | 字段/方法 | 集合類型外層包裹元素名 |
| @XmlTransient | 字段/方法 | 忽略該字段不參與序列化 |
| @XmlType | 類 | 指定元素順序 propOrder |
| @XmlJavaTypeAdapter | 字段/方法/類 | 自定義類型適配器(如日期格式化) |
JAXBContext 創建開銷大,應作為單例或緩存復用JAXBException、SAXException、IOException,轉換為業務異常@XmlSchema、package-info.java@XmlJavaTypeAdapter 適配 XmlAdapter 統一格式Marshaller.JAXB_FORMATTED_OUTPUT = false掌握四大 XML 解析技術的優劣與適用邊界,是 Java 後端開發者處理異構系統集成、配置管理、報文解析的核心技能。現代項目中,JAXB 應作為首選方案,特殊場景再輔以 StAX/SAX。