輕量級數據交換、配置文件、伺服器回傳結構化數據。但 DOM 樹模型記憶體佔用大,SAX 事件模型代碼複雜。J2ME 專用輕量解析器 (KXML, NanoXML, TinyXML, MinXML) 在 10~30 KB JAR 內提供折中方案。
| 模式 | 原理 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|---|
| 樹模型 (DOM-like) | 整個 XML 載入記憶體為節點樹 | 隨機訪問、XPath 風格查詢、修改方便 | 記憶體峰值高,大文檔易 OOM | 小型配置/回傳 (< 10 KB) |
| 事件模型 (SAX-like) | 流式解析,回調 startElement/endElement/text | 常數記憶體、速度快 | 只能單向遍歷、需自維狀態機 | 大文檔、串流數據、極限記憶體環境 |
下載 tinyxml.jar (約 15 KB) → 放入 WTK 專案 lib/ → 專案屬性 Libraries 添加。
<?xml version="1.0"?>
<mail>
<From>Developer</From>
<To>Students</To>
<Cc>Faculty</Cc>
<Date>30</Date>
<Subject>Integration</Subject>
<Body Language="English">This is J2ME!!!!</Body>
</mail>
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
import java.io.*;
import gd.xml.*;
import gd.xml.tiny.*;
public class TinyTreeDemo extends MIDlet implements CommandListener {
private Display display;
private Form form;
private TextField urlField;
private Command cmdGo, cmdExit;
private String url = "https://127.0.0.1:8000/mail.xml";
public TinyTreeDemo() {
display = Display.getDisplay(this);
form = new Form("XML Parser Demo");
urlField = new TextField("URL", url, 128, TextField.URL);
cmdGo = new Command("Parse", Command.OK, 1);
cmdExit = new Command("Exit", Command.EXIT, 1);
form.append(urlField);
form.addCommand(cmdGo); form.addCommand(cmdExit);
form.setCommandListener(this);
}
protected void startApp() { display.setCurrent(form); }
protected void pauseApp() {}
protected void destroyApp(boolean u) {}
public void commandAction(Command c, Displayable d) {
if (c == cmdExit) { notifyDestroyed(); return; }
if (c == cmdGo) { new Thread(this::parseXml).start(); }
}
private void parseXml() {
try {
ParsedXML root = TinyParser.parseXML(urlField.getString());
displayParsed(root);
} catch (Exception e) {
showAlert("解析失敗", e.getMessage(), AlertType.ERROR);
}
}
private void displayParsed(ParsedXML node) {
StringBuilder sb = new StringBuilder();
dumpNode(node, sb, 0);
showAlert("解析結果", sb.toString(), AlertType.INFO);
}
private void dumpNode(ParsedXML n, StringBuilder sb, int indent) {
String prefix = " ".repeat(indent);
String typeName = n.getTypeName(); // "tag", "text", ...
String name = n.getName(); // 標籤名
if (name != null) typeName += "<" + name + ">";
sb.append(prefix).append(typeName).append("\n");
String content = n.getContent();
if (content != null && !content.isEmpty())
sb.append(prefix).append(" text: ").append(content).append("\n");
// 屬性
Enumeration attrs = n.attributes();
while (attrs.hasMoreElements()) {
String an = (String) attrs.nextElement();
sb.append(prefix).append(" @").append(an).append("=").append(n.getAttribute(an)).append("\n");
}
// 子元素
Enumeration children = n.elements();
while (children.hasMoreElements())
dumpNode((ParsedXML) children.nextElement(), sb, indent+1);
}
private void showAlert(String title, String msg, AlertType type) {
Alert a = new Alert(title, msg, null, type);
a.setTimeout(Alert.FOREVER);
display.setCurrent(a, form);
}
}
TinyParser.parseXML(String url):從 HTTP/文件/字串解析,返回根節點 ParsedXML。node.getTypeName():節點類型 ("tag", "text", "pi", "comment"…)。node.getName():標籤名 (對 tag 節點)。node.getContent():文本內容 (對 text 節點或 tag 內文本)。node.attributes():返回屬性名 Enumeration。node.getAttribute(name):取屬性值。node.elements():返回子元素 Enumeration。HttpConnection.getLength() 或 Content-Length,超過 20 KB 建議改用 SAX 模式 (KXML/NanoXML 均支援)。root = null; System.gc();。<?xml encoding="UTF-8"?>,J2ME 內部以 UTF-16 存儲字串。