首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Java XML 解析三大流派:DOM、SAX、StAX 與 JAXB 實戰

     編輯:Java 程式設計入門

前言:三大標準解析模式對比

Java 生態提供三種主流 XML 解析 API,各有優勢場景:

模式特點記憶體適用場景
DOM樹狀模型,一次性載入整個文檔高(佔用大)小型 XML、需隨機訪問、頻繁修改
SAX事件驅動,流式讀取,觸發回調低(不載入樹)大型 XML、單次順序讀取、記憶體受限
StAX拉取式流解析,程式主動迭代事件低大型 XML、需精確控制解析流程、雙向讀寫

SAX 實戰:配置文件解析範例

繼承 DefaultHandler 覆寫關鍵回調方法:

public class ConfigParser extends DefaultHandler {
    private String currentSection;
    public SysConfigItem sysConfig;
    public List<InterfaceConfigItem> interfaceList = new ArrayList<>();
    // ... 其他列表

    @Override
    public void startDocument() {
        sysConfig = new SysConfigItem();
        // 初始化各列表
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attrs) {
        if ("Item".equalsIgnoreCase(qName) && attrs.getLength() > 0) {
            // 根據當前區段建立對應對象並加入列表
            switch (currentSection) {
                case "SysConfigItem": sysConfig = new SysConfigItem(attrs); break;
                case "InterfaceConfigItems": interfaceList.add(new InterfaceConfigItem(attrs)); break;
                // ...
            }
        } else {
            currentSection = qName; // 記錄進入的區段名
        }
    }
    // endElement、characters 視需求實作
}

反射通用基類:自動映射屬性

public class ConfigItemBase {
    private static final DateFormat DF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public ConfigItemBase(Attributes attrs) {
        Field[] fields = this.getClass().getDeclaredFields();
        for (Field f : fields) {
            f.setAccessible(true);
            String attrVal = attrs.getValue(f.getName());
            if (attrVal == null) continue;
            try {
                String type = f.getType().getSimpleName();
                if ("String".equalsIgnoreCase(type)) f.set(this, attrVal);
                else if ("Integer".equalsIgnoreCase(type)) f.set(this, Integer.valueOf(attrVal));
                else if ("Double".equalsIgnoreCase(type)) f.set(this, Double.valueOf(attrVal));
                else if ("Date".equalsIgnoreCase(type)) f.set(this, DF.parse(attrVal));
                else System.out.println("Warning: Unhandled field " + f.getName());
            } catch (Exception e) { e.printStackTrace(); }
        }
    }
}

重頭戲:JAXB(Java Architecture for XML Binding)

JAXB 以註解驅動,將 XML 直接綁定為 Java 對象,開發效率最高,適合結構固定的業務報文。

實戰場景:InterBOSS 協議報文解析

報文結構特點:外層 InterBOSS,內層 SvcCont 為 CDATA 包裹的內層 XML。

<?xml version="1.0" encoding="UTF-8"?>
<InterBOSS>
    <Version>0100</Version>
    <SvcCont><![CDATA[
        <?xml version="1.0"?>
        <batchSyncOrderRelationReq>...</batchSyncOrderRelationReq>
    ]]></SvcCont>
</InterBOSS>

實體類註解映射

@XmlRootElement(name = "batchSyncOrderRelationReq")
@XmlAccessorType(XmlAccessType.FIELD)
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 xml) throws BusinessException {
        try {
            // 1. 解析外層 Head
            JAXBContext headCtx = JAXBContext.newInstance(MessageHead.class);
            MessageHead head = (MessageHead) headCtx.createUnmarshaller()
                .unmarshal(new StringReader(xml));

            // 2. 解析 CDATA 內層 Body
            JAXBContext bodyCtx = JAXBContext.newInstance(BatchSyncOrderRelationReq.class);
            BatchSyncOrderRelationReq body = (BatchSyncOrderRelationReq) bodyCtx.createUnmarshaller()
                .unmarshal(new StringReader(head.getSvcCont().trim()));
            body.setHead(head);
            return body;
        } 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;
    // ... 其餘 20+ 欄位皆用 @XmlElement 映射
}

關鍵註解說明

  • @XmlRootElement:標識根元素,name 對應 XML 標籤名。
  • @XmlAccessorType(XmlAccessType.FIELD):直接綁定字段,無需寫 getter/setter 也能序列化。
  • @XmlElement(name="..."):指定 XML 子元素名稱,支援集合自動解析為 List。
  • @XmlAttribute:映射 XML 屬性(本例未用)。

JAXB 最佳實踐提示

  1. Context 重用:JAXBContext 建立開銷大,建議單例緩存。
  2. 命名空間處理:涉及命名空間時使用 @XmlSchema 包級註解。
  3. CDATA 處理:如本例所示,分兩階段解析——先取外層,再解析內層字串。
  4. 異常轉換:將 JAXBException 包裝為業務異常,保持介面乾淨。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved