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

XML 節點轉 JavaBean 並持久化入庫:半自動遞迴解析框架

     編輯:Java 相關知識

面對無 DTD/Schema、結構不規範(如多層巢狀 pig → content → pighead)的 XML,無法使用自動化綁定工具。本文提出基於「多態 + 遞迴」的半自動解析/入庫框架:自動處理共同邏輯,業務差異由具體類別實作。

三棵樹的一致性映射

關係類型XMLJavaBean資料庫
原子屬性 (1:1)Attribute 或單純 ElementString 欄位主表欄位
複合屬性 (1:1)含子元素的 Element實作 BusiNode 的單一欄位子表(外鍵指向主表)
複合屬性 (N:1)重複出現的 ElementList/Set<BusiNode>子表(外鍵指向主表)

核心介面:BusiNode


public interface BusiNode {
    List<String> getAtomicPropNames();           // 原子屬性名(均為 String)
    List<String> getXmlAttributes();             // 對應 XML Attribute 的屬性
    List<String> getXmlAtomicElements();         // 對應 XML 原子 Element 的屬性
    Map<String, Class> getCollectionPropsMap();  // 集合屬性名 → 元素類別
    List<String> getBusiNodePropNames();         // 單一複合屬性名
    Element getXmlElementParent(Element root);   // 取得子元素父節點(處理多層巢狀)
    Iterator<Element> getCollectionElementIterator(Element parent, String name); // 集合元素迭代器
    void parseFromXML(Element root);             // 遞迴解析進入點
}

預設實作:DefaultBusiNode

利用反射自動發現屬性:

  • 原子屬性 = 所有 String 型別欄位
  • 單一複合屬性 = 實作 BusiNode 的欄位
  • 集合屬性 = 需手動註冊 Map<屬性名, 元素Class>(Java 1.4 無泛型資訊)

解析順序:Attribute → 原子 Element → 單一複合 → 集合複合。持久化順序:主表 → 集合子表 → 單一子表。

關鍵程式碼片段


// 解析 XML Attribute
protected void parseAttributesFromXml(Element root) {
    for (String name : getXmlAttributes()) {
        Attribute att = root.attribute(name);
        if (att != null) PropertyUtils.setProperty(this, name, att.getValue());
    }
}

// 解析集合屬性(遞迴)
protected void parseCollectionPropsFromXml(Element root) {
    Element parent = getXmlElementParent(root);
    for (Map.Entry<String, Class> entry : getCollectionPropsMap().entrySet()) {
        String name = entry.getKey();
        Class type = entry.getValue();
        Collection coll = (Collection) PropertyUtils.getProperty(this, name);
        for (Element child : getCollectionElementIterator(parent, name)) {
            BusiNode node = type.newInstance();
            node.parseFromXML(child);
            coll.add(node);
        }
    }
}

// 持久化:先存主記錄取得 ID,再遞迴存子記錄
private Long saveBusiNode(BusiNode node, Long parentId) {
    Long id = saveBareNode(node, parentId);  // 插入主表,返回自增 ID
    // 存集合子節點
    for (Map.Entry<String, Class> e : node.getCollectionPropsMap().entrySet()) {
        for (BusiNode child : (Collection) PropertyUtils.getProperty(node, e.getKey()))
            saveBusiNode(child, id);
    }
    // 存單一子節點
    for (String name : node.getBusiNodePropNames()) {
        BusiNode child = (BusiNode) PropertyUtils.getProperty(node, name);
        if (child != null) saveBusiNode(child, id);
    }
    return id;
}

業務類別實作範例


public class Pig implements BusiNode {
    private String id, name;           // 原子屬性
    private PigHead head;              // 單一複合
    private List<PigFoot> feet;        // 集合複合

    // 實作介面方法...
    public List<String> getXmlAttributes() { return Arrays.asList("id"); }
    public List<String> getXmlAtomicElements() { return Arrays.asList("name"); }
    public List<String> getBusiNodePropNames() { return Arrays.asList("head"); }
    public Map<String, Class> getCollectionPropsMap() {
        return Collections.singletonMap("feet", PigFoot.class);
    }
    public Element getXmlElementParent(Element root) {
        return root.element("content") != null ? root.element("content") : root;
    }
    public Iterator<Element> getCollectionElementIterator(Element parent, String name) {
        return parent.elementIterator(name);  // 或 parent.element("content").elementIterator(name)
    }
}

框架限制與適用場景

  • 所有業務欄位必須為 String/VARCHAR,非業務欄位不可為 String
  • Bean 名與表名一一對應,欄位名與 XML 屬性/元素名一一對應
  • 適合:XML 結構固定但不規範、無 Schema、需快速開發解析入庫邏輯的專案
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved