XML Viewer in Java
This example shows the XML document in the form of a tree.
---------------- XMLView.java ------------------ import java.io.*; import java.util.*; import java.nio.file.*; import javafx.application.*; import javafx.stage.*; import javafx.scene.*; import javafx.scene.control.*; import javafx.scene.image.*; import javafx.scene.layout.*; import javafx.beans.property.*; import javax.xml.parsers.*; import org.w3c.dom.*; public class XMLView extends Application { Label label; TreeTableView<org.w3c.dom.Node> treeTableView; @Override public void start(Stage stage) { List<String> p = getParameters().getRaw(); File file; if (!p.isEmpty()) { file = new File(p.get(0)); if (!file.isFile()) throw new RuntimeException(file.getName() + " file not found"); } else { file = new File("sample.xml"); if (!file.exists()) createDemo(file); } label = new Label(); treeTableView = createTreeTableView(file); BorderPane layout = new BorderPane(); layout.setCenter(treeTableView); layout.setBottom(label); stage.setScene(new Scene(layout, 600, 400)); stage.show(); } TreeTableView<org.w3c.dom.Node> createTreeTableView(File file) { TreeTableView<org.w3c.dom.Node> treeTableView = new TreeTableView<>(createTreeItems(file)); treeTableView.setShowRoot(true); treeTableView.setColumnResizePolicy(TreeTableView.CONSTRAINED_RESIZE_POLICY); TreeTableColumn<org.w3c.dom.Node, TreeItem<org.w3c.dom.Node>> nameColumn = new TreeTableColumn<>("Name"); nameColumn.setCellValueFactory( (TreeTableColumn.CellDataFeatures<org.w3c.dom.Node, TreeItem<org.w3c.dom.Node>> cellData) -> new ReadOnlyObjectWrapper<TreeItem<org.w3c.dom.Node>>(cellData.getValue()) ); Image[] images = new Image[tagNames.length]; try { Image image = new Image(getClass().getResourceAsStream("image.png")); for(int i = 0; i < images.length; i++) { images[i] = new WritableImage(image.getPixelReader(), i * 16, 0, 16, 16); } } catch (Exception e) {} nameColumn.setCellFactory(column -> { TreeTableCell<org.w3c.dom.Node, TreeItem<org.w3c.dom.Node>> cell = new TreeTableCell<org.w3c.dom.Node, TreeItem<org.w3c.dom.Node>>() { ImageView[] imageView = new ImageView[images.length]; { for(int i = 0; i < imageView.length; i++) imageView[i] = new ImageView(images[i]); } @Override protected void updateItem(TreeItem<org.w3c.dom.Node> item, boolean empty) { super.updateItem(item, empty); if (item != null && !empty) { org.w3c.dom.Node node = item.getValue(); if (item.getValue() != null) { String s = node.getNodeName(); setText(s == null ? "" : s.trim()); setGraphic(imageView[typeIndex(node.getNodeType())]); return; } } setText(null); setGraphic(null); } }; return cell; }); nameColumn.setPrefWidth(300); nameColumn.setSortable(false); treeTableView.getColumns().add(nameColumn); TreeTableColumn<org.w3c.dom.Node, String> valueColumn = new TreeTableColumn<>("Value"); valueColumn.setCellValueFactory(cellData -> { TreeItem<org.w3c.dom.Node> item = cellData.getValue(); org.w3c.dom.Node childNode = item.getValue(); if (childNode != null) { String s = childNode.getNodeType() == org.w3c.dom.Node.DOCUMENT_TYPE_NODE ? ((DocumentType)childNode).getInternalSubset() : childNode.getNodeValue(); if (s != null) { return new ReadOnlyObjectWrapper<String>(s.trim()); //return new ReadOnlyObjectWrapper<String>(s.trim().replaceAll("\\s+", " ")); } } return null; }); valueColumn.setPrefWidth(100); valueColumn.setSortable(false); treeTableView.getColumns().add(valueColumn); treeTableView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> { if (newValue != null) { org.w3c.dom.Node node = newValue.getValue(); if (node != null) { label.setText(tagNames[typeIndex(node.getNodeType())]); return; } } label.setText(""); }); treeTableView.getSelectionModel().selectFirst(); return treeTableView; } TreeItem<org.w3c.dom.Node> createTreeItems(File file) { TreeItem<org.w3c.dom.Node> root = null; try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(file); doc.getDocumentElement().normalize(); root = new TreeItem<>(doc); root.setExpanded(true); addChildrenItem(root); } catch (Exception e) { e.printStackTrace(); } return root; } void addChildrenItem(TreeItem<org.w3c.dom.Node> root) { org.w3c.dom.Node node = root.getValue(); if (node.hasAttributes()) { NamedNodeMap attrs = node.getAttributes(); for(int i = 0; i < attrs.getLength(); i++) { root.getChildren().add(new TreeItem<org.w3c.dom.Node>(attrs.item(i))); } } NodeList list = node.getChildNodes(); for (int i = 0; i < list.getLength(); i++) { org.w3c.dom.Node childNode = list.item(i); if (childNode != null && (childNode.getNodeType() != org.w3c.dom.Node.TEXT_NODE || (childNode.getNodeValue() != null && childNode.getNodeValue().trim().length() > 0))) { TreeItem<org.w3c.dom.Node> treeItem = new TreeItem<>(childNode); treeItem.setExpanded(true); root.getChildren().add(treeItem); addChildrenItem(treeItem); } } } final String tagNames[] = {"Not considered", "Element", "Attribute", "Text", "CDATA section", "Processing Instruction", "Comment", "Document", "Document Type"}; int typeIndex(int t) { switch (t) { case org.w3c.dom.Node.ELEMENT_NODE: return 1; case org.w3c.dom.Node.ATTRIBUTE_NODE: return 2; case org.w3c.dom.Node.TEXT_NODE: return 3; case org.w3c.dom.Node.CDATA_SECTION_NODE: return 4; case org.w3c.dom.Node.PROCESSING_INSTRUCTION_NODE: return 5; case org.w3c.dom.Node.COMMENT_NODE: return 6; case org.w3c.dom.Node.DOCUMENT_NODE: return 7; case org.w3c.dom.Node.DOCUMENT_TYPE_NODE: return 8; } return 0; } void createDemo(File file) { StringBuilder sb = new StringBuilder(); sb.append("<?xml version=\"1.0\"?>\n"); sb.append(" <!DOCTYPE DocType [<!ENTITY name \"Value\">]>\n"); sb.append(" <?Target Instruction?>\n"); sb.append(" <!--Comment-->\n"); sb.append("<Element Attribute=\"Attribute\">\n"); sb.append(" <Element>\n"); sb.append(" Text &name;\n"); sb.append(" </Element>\n"); sb.append(" <![CDATA[CDATA Section]]>\n"); sb.append(" <EmptyElement/>\n"); sb.append("</Element>\n"); try { Files.write(file.toPath(), sb.toString().getBytes()); } catch (Exception e) { } } }