XML 本質是層次化數據:單一根元素、巢狀子元素、屬性附加。樹形視圖(JTree)天然匹配這種結構——根節點對應文檔根元素,分支對應子元素,葉子節點對應文本內容或屬性。用戶可直觀展開/摺疊、定位節點、理解文檔架構。
xercesImpl.jar、xml-apis.jar,置於 Classpath。JTree、DefaultTreeModel、DefaultMutableTreeNode、JScrollPane、JFrame。public class XTree extends JTree {
// 域
private DefaultMutableTreeNode treeNode; // 模型根節點
private DocumentBuilderFactory dbf; // JAXP 工廠
private DocumentBuilder db; // DOM 構建器
private Document doc; // 解析後文檔對象
// 構造器
public XTree(String xmlText) throws ParserConfigurationException { ... }
// 核心私有方法
private Node parseXml(String text) { ... } // 字符串 -> DOM Node
private DefaultMutableTreeNode createTreeNode(Node) { ... } // DOM Node -> Swing 树節點 (遞歸)
private String getNodeType(Node) { ... } // 節點類型 -> 可讀字符串
}
private Node parseXml(String text) {
try {
ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes("UTF-8"));
doc = db.parse(bis);
return doc.getDocumentElement(); // 返回根元素節點
} catch (Exception e) {
e.printStackTrace();
System.exit(0); // 簡化版直接退出,後續改進
}
return null;
}
private DefaultMutableTreeNode createTreeNode(Node domNode) {
// 節點顯示文本:元素顯示標籤名,文本節點顯示內容
String display = (domNode.getNodeType() == Node.TEXT_NODE)
? domNode.getNodeValue()
: domNode.getNodeName();
DefaultMutableTreeNode swingNode = new DefaultMutableTreeNode(display);
// 處理屬性:作為子節點展示 [Attribute] name="value"
NamedNodeMap attrs = domNode.getAttributes();
if (attrs != null) {
for (int i = 0; i < attrs.getLength(); i++) {
Node attr = attrs.item(i);
swingNode.add(new DefaultMutableTreeNode(
"[Attribute] --> " + attr.getNodeName() + "=\"" + attr.getNodeValue() + "\""));
}
}
// 遞歸處理子節點
if (domNode.hasChildNodes()) {
NodeList children = domNode.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node child = children.item(i);
if (child.getNodeType() == Node.ELEMENT_NODE) {
swingNode.add(createTreeNode(child)); // 元素節點遞歸
} else if (child.getNodeType() == Node.TEXT_NODE) {
String text = child.getNodeValue().trim();
if (!text.isEmpty() && !text.equals("\n") && !text.equals("\r\n")) {
swingNode.add(createTreeNode(child)); // 非空白文本節點
}
}
}
}
return swingNode;
}
private String getNodeType(Node node) {
switch (node.getNodeType()) {
case Node.ELEMENT_NODE: return "Element";
case Node.ATTRIBUTE_NODE: return "Attribute";
case Node.TEXT_NODE: return "Text";
case Node.CDATA_SECTION_NODE: return "CDATA Section";
case Node.COMMENT_NODE: return "Comment";
case Node.DOCUMENT_NODE: return "Document";
// ... 其他類型
default: return "???";
}
}
public class XTreeTester extends JFrame {
private XTree xTree;
private JScrollPane scrollPane;
public XTreeTester(String title, String xml) throws ParserConfigurationException {
super(title);
setLayout(new BorderLayout());
xTree = new XTree(xml);
scrollPane = new JScrollPane(xTree);
add(scrollPane, BorderLayout.CENTER);
setSize(400, 300);
centerOnScreen();
setVisible(true);
}
// main 方法:讀取命令行指定 .xml 文件,傳入構造器
}
java -cp .;xercesImpl.jar;xml-apis.jar XTreeTester sample.xml
| 亮點 | 待改進 |
|---|---|
| 封裝性好:XTree 獨立可複用,測試類極簡 | 異常處理粗暴 (System.exit) |
| 遞歸算法清晰處理混合內容 (元素+文本+屬性) | 無編輯能力 (setEditable(false)) |
| 屬性節點獨立展示,語義明確 | 無默認視圖,必須提供 XML 文件 |
| 採用標準 JAXP API,解析器可換裝 | 大文檔 DOM 佔用記憶體高 |
第二篇將構建 雙分欄編輯器框架(JSplitPane 分割樹視圖與文本編輯區),增強 XTree:默認歡迎樹、優雅異常處理、公開刷新 API,為文件操作奠基。