外部系統提供無 DTD/Schema 的 XML,且 XML 結構與業務物件模型不完全對應 (如多層 content 節點)。無法使用 JAXB 等自動綁定工具,需手工解析但又想復用共同邏輯。
public interface BusiNode {
List getAtomicPropNames(); // 基本型別屬性 (String)
List getXMLAttributes(); // 對應 XML Attribute 的屬性名
List getXMLAtomicElements(); // 對應 XML 子元素(文字) 的屬性名
Map> getCollectionPropsMap(); // 集合屬性: 屬性名 -> 元素類別
List getBusiNodePropNames(); // 單一子節點屬性 (亦實作 BusiNode)
Element getXMLElementParent(Element root); // 取得當前節點的 XML 父元素 (處理多層 content)
Iterator getCollectionElementIterator(Element parent, String propName); // 集合子元素迭代器
void parseFromXML(Element root); // 遞迴解析入口
}
PropertyUtils (Apache Commons BeanUtils) 以屬性名字串動態設值。String,避免類型轉換複雜度。Map<屬性名, 元素Class> (Java 1.4 無泛型擷取限制)。
public class BusiNodeDAO {
public Long save(BusiNode node, Long parentId) {
Long id = saveBareNode(node, parentId); // 寫入基本欄位 + parent_id
// 寫入集合子節點
for (Map.Entry> e : node.getCollectionPropsMap().entrySet()) {
Collection> coll = (Collection>) PropertyUtils.getProperty(node, e.getKey());
for (Object child : coll) save((BusiNode) child, id);
}
// 寫入單一子節點
for (String prop : node.getBusiNodePropNames()) {
BusiNode child = (BusiNode) PropertyUtils.getProperty(node, prop);
if (child != null) save(child, id);
}
return id;
}
// saveBareNode 利用反射動態生成 INSERT SQL,回傳自增主鍵
}
id (PK) 與 parent_id (FK) 欄位,名稱統一。VARCHAR,配合 String 屬性避免類型轉換。| 優點 | 缺點/限制 |
|---|---|
| 大幅減少重複解析/入庫代碼 | 需手工寫 Bean、建表、註冊集合類別 |
| 統一異常處理、事務控制 | 基本型別限定 String,無法直接支援 Date/Number |
| 應對不規範 XML 結構靈活 | Java 1.4 需手動註冊集合泛型類別 |