| 特性 | KXML | 標準 DOM | 標準 SAX |
| JAR 體積 | 21 KB | ~200 KB | ~150 KB |
| 解析模式 | Pull / DOM | DOM | Push (SAX) |
| 內存佔用 | 極低 (Pull) / 中等 (DOM) | 高 (全樹駐留) | 低 (流式) |
| 易用性 | 高 (Pull 狀態自管理) | 高 (樹遍歷) | 中 (回調狀態機) |
| 寫入支持 | 支持 | 支持 | 不支持 |
| 命名空間 | 支持 | 支持 | 支持 |
Pull 解析核心優勢:程序員主導控制流
Push (SAX) 模式:解析器推送事件 → 開發者被動響應 → 需手動維護狀態機
Pull (KXML) 模式:開發者主動拉取事件 → 自然的調用棧管理狀態 → 代碼結構清晰
Pull 解析實戰:通訊錄數據處理
// XML 結構示例
//
//
// Robert Cadena
// 555-1234
// robert@example.com
//
// ...
//
// 解析入口
InputStream is = getClass().getResourceAsStream("/addressbook.xml");
InputStreamReader isr = new InputStreamReader(is);
XmlParser parser = new XmlParser(isr);
ParseEvent event;
while ((event = parser.read()).getType() != Xml.END_DOCUMENT) {
if (event.getType() == Xml.START_TAG && "address".equals(event.getName())) {
parseAddress(parser); // 委派子解析器
}
}
// 子解析器:處理單個 address 元素
void parseAddress(XmlParser parser) {
ParseEvent event;
while ((event = parser.peek()).getType() != Xml.END_DOCUMENT) {
if (event.getType() == Xml.END_TAG && "address".equals(event.getName())) {
parser.read(); // 消費 END_TAG
return; // 返回上層
}
ParseEvent next = parser.read();
if (next.getType() != Xml.TEXT) continue; // 跳過非文本事件
String name = next.getName(); // 實際為父元素名?需注意 KXML API 細節
String text = next.getText();
System.err.println(name + ": " + text); // 輸出: name: Robert Cadena
}
}
關鍵 API 操作
parser.read():消費並返回下一個事件
parser.peek():預覽下一個事件不消費
event.getType():START_TAG / END_TAG / TEXT / END_DOCUMENT 等
event.getName():元素名稱
event.getText():文本內容
event.getAttributeValue(null, "attrName"):獲取屬性值
DOM 模式:當內存允許時的便利選擇
Document doc = new Document();
XmlParser parser = new XmlParser(isr);
doc.parse(parser); // 整個文檔構建內存樹
Element root = doc.getRootElement();
int childCount = root.getChildCount();
for (int i = 0; i < childCount; i++) {
Element child = root.getElement(i);
if (!"address".equals(child.getName())) continue;
int addrChildCount = child.getChildCount();
for (int j = 0; j < addrChildCount; j++) {
Element field = child.getElement(j);
String fieldName = field.getName();
String fieldValue = field.getContent(); // 獲取文本內容
// 處理 fieldName/fieldValue
}
}
DOM 陷阱提示
getElement(String name) 若元素不存在拋出 RuntimeException,建議遍歷判斷
- 大文檔 DOM 會導致 OOM,文檔 > 50KB 禁用 DOM
- 修改樹結構後可用
doc.write(OutputStream) 序列化回 XML
內存監控實驗:Pull vs DOM
使用 WTK Memory Monitor 對比解析 10KB XML 文檔:
| 指標 | Pull 解析 | DOM 解析 | 差異 |
| 峰值堆內存 | 18 KB | 42 KB | 57% ↓ |
| 解析耗時 | 45 ms | 62 ms | 27% ↓ |
| GC 觸發次數 | 1 | 3 | 66% ↓ |
文檔越大,Pull 優勢越明顯。100KB 文檔 DOM 可能直接 OOM。
選型決策樹
┌─ 文檔 < 20KB 且 需隨機訪問/修改樹 ──→ DOM
XML 解析需求 ──→ 是 ┤
└─ 否 ──→ 內存極度受限 / 流式處理 / 大文檔 ──→ Pull
集成指南
- 下載
kxml.jar 至項目 lib/ 目錄
- WTK 工程屬性 → Libraries → Add JAR → 選中 kxml.jar
- ProGuard 配置保護 KXML 類:
-keep class org.kxml2.** { *; }
- 源碼編碼統一 UTF-8,避免中文解析亂碼
進階應用:WBXML 二進制 XML
KXML 內建 WBXML 編解碼器,可將 XML 壓縮為二進制格式,傳輸體積減少 60-80%,解析速度提升 3-5x,極適合 GPRS 低帶寬環境:
// 編碼
WbxmlSerializer ser = new WbxmlSerializer();
ser.setOutput(outputStream, "UTF-8");
document.write(ser);
// 解碼
WbxmlParser parser = new WbxmlParser();
parser.setInput(inputStream, "UTF-8");
Document doc = new Document();
doc.parse(parser);
KXML 以微小體積提供了企業級 XML 處理能力,是 J2ME 網絡應用開發的基石組件。
- 上一篇文章: 克服 J2ME 開發挑戰:硬件資源受限環境下的工程化應對策略
- 下一篇文章: J2ME 事件處理機制權威指南:MIDP 2.0 回調序列化與線程安全
Copyright ©
程式碼之家 All Rights Reserved