XML 擁有跨平台、人類可讀優勢,但解析器消耗 CPU/內存。MIDP 1.0 無原生支持,JSR 182 提供標準但需特定實現。實際開發中主流選擇第三方輕量解析器:**kXML(增量解析)** 與 **NanoXML(樹模型解析)**。
| 特性 | kXML (Pull/增量) | NanoXML (DOM/樹模型) |
|---|---|---|
| 解析方式 | 事件流式,`parser.read()` 逐個返回 `ParseEvent` | 一次性構建完整對象樹 |
| 內存佔用 | 極低,適合大文檔 | 與文檔大小成正比,大文檔風險高 |
| 編程模型 | 狀態機,需手動維護上下文(如 `inItem` 標誌) | 樹導航,`getChildren()` 直觀查找 |
| 驗證支持 | 非驗證型,速度快 | 非驗證型,速度快 |
| 適用場景 | 流式數據、大文檔、內存極受限設備 | 小文檔、需多次隨機訪問節點、開發效率優先 |
XmlParser parser = new XmlParser(new InputStreamReader(inputStream));
while (true) {
ParseEvent event = parser.read();
switch (event.getType()) {
case Xml.START_TAG: // 處理標籤開始
case Xml.END_TAG: // 處理標籤結束
case Xml.TEXT: // 處理文本內容
case Xml.END_DOCUMENT: return; // 結束
}
}
private void parsekXMLItems(XmlParser parser, Vector items) throws IOException {
boolean inItem = false;
while (true) {
ParseEvent event = parser.read();
switch (event.getType()) {
case Xml.START_TAG:
if ("item".equals(event.getName())) inItem = true;
break;
case Xml.TEXT:
if (inItem) items.addElement(event.getText());
break;
case Xml.END_TAG:
if ("item".equals(event.getName())) inItem = false;
break;
case Xml.END_DOCUMENT:
return;
}
}
}
關鍵點:用布爾標誌追蹤是否處于目標標籤內,文本事件直接入庫。
kXMLElement root = new kXMLElement();
root.parseFromReader(reader); // 一次性構建樹
Vector list = root.getChildren(); // 獲取根節點子元素
for (int i = 0; i < list.size(); i++) {
kXMLElement node = (kXMLElement) list.elementAt(i);
if ("item".equals(node.getTagName())) {
items.addElement(node.getContents()); // 直接取文本內容
}
}
代碼更直觀,但整個文檔常駐內存。
public class XMLTest extends MIDlet {
private static String xmlDoc = "- apple
- orange
- pear
";
protected void startApp() {
Display display = Display.getDisplay(this);
// String[] items = parseUsingNanoXML(xmlDoc); // 切換解析器只需改這行
String[] items = parseUsingkXML(xmlDoc);
display.setCurrent(new List("Items", List.IMPLICIT, items, null));
}
// parseUsingkXML / parseUsingNanoXML 方法見上文
// 內部類 ItemList 實現 CommandListener 處理退出
}
J2ME XML 解析沒有銀彈,**kXML 穩健適用於大多數生產場景**,NanoXML 適合快速原型與小數據。建議項目標準化封裝 `XmlParserService` 接口,底層可熱插拔兩種實現,應對不同接口協議需求。