我尝试将以下XML文件解析为树视图。
工作正常。
但我需要区分" Endnodes"用鼠标选择节点时的空节点。
我尝试使用selectedItem.getChildren()。size()和selectedItem.isLeaf()。
但两者都为" endnode"提供了相同的结果。空的"测试"节点。
不幸的是我无法更改xml结构,因为ist是自动生成的。
有人可以帮帮我吗?
<root>
<type_1>
<element_1>
EndNode
</element_1>
</type_1>
<type_2>
<element_2>
<test>Endnode</test>
<test/>
</element_2>
</type_2>
</root>
我从我在SO找到的一个例子开始,并根据我的需要对其进行修改。
JavaFX的
public static TreeItem<String> readData(File file) throws SAXException, ParserConfigurationException, IOException {
SAXParserFactory parserFactory = SAXParserFactory.newInstance();
SAXParser parser = parserFactory.newSAXParser();
XMLReader reader = parser.getXMLReader();
TreeItemCreationContentHandler contentHandler = new TreeItemCreationContentHandler();
// parse file using the content handler to create a TreeItem representation
reader.setContentHandler(contentHandler);
reader.parse(file.toURI().toString());
// use first child as root (the TreeItem initially created does not contain data from the file)
TreeItem<String> item = contentHandler.item.getChildren().get(0);
contentHandler.item.getChildren().clear();
return item;
}
@Override
public void initialize(URL url, ResourceBundle rb) {
TreeItem<String> root;
try {
root = readData(new File("test.xml"));
treeType.setRoot(root);
} catch (Exception ex) {
}
treeType.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<TreeItem<String>>() {
@Override
public void changed(
ObservableValue<? extends TreeItem<String>> observable, TreeItem<String> old_val,
TreeItem<String> new_val
) {
TreeItem<String> selectedItem = new_val;
System.out.println(selectedItem.getChildren().size() + " : " + selectedItem.isLeaf());
}
}
);
-
class TreeItemCreationContentHandler extends DefaultHandler {
public TreeItem<String> item = new TreeItem<>();
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
this.item = this.item.getParent();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
TreeItem<String> item = new TreeItem<>(qName);
this.item.getChildren().add(item);
this.item = item;
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
String s = String.valueOf(ch, start, length).trim();
if (!s.isEmpty()) {
// add text content as new child
this.item.getChildren().add(new TreeItem<>(s));
}
}
}
附加组件: 我也很乐意提示如何自动突出显示终端节点。
答案 0 :(得分:1)
通过使用TreeView<String>
,您无法区分元素和字符数据。相反,定义一个封装它的类(或多个类)。 E.g。
public class XMLNode {
private final String text ;
private final boolean characterData ;
public XMLNode(String text, boolean isCharacterData) {
this.text = text ;
this.characterData = isCharacterData ;
}
public boolean isElement() {
return ! characterData ;
}
public boolean isCharacterData() {
return characterData ;
}
@Override
public boolean equals(Object obj) {
if (! (obj instanceof XMLNode)) {
return false ;
}
XMLNode other = (XMLNode) obj ;
return other.characterData == characterData
&& Objects.equals(other.text, text);
}
@Override
public int hashCode() {
return Objects.hash(text, characterData);
}
@Override
public String toString() {
return text ;
}
}
现在,您可以将TreeView<String>
和TreItem<String>
更改为TreeView<XMLNode>
和TreeItem<XMLNode>
,然后执行
class TreeItemCreationContentHandler extends DefaultHandler {
public TreeItem<XMLNode> item = new TreeItem<>();
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
this.item = this.item.getParent();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
TreeItem<XMLNode> item = new TreeItem<>(new XMLNode(qName, false));
this.item.getChildren().add(item);
this.item = item;
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
String s = String.valueOf(ch, start, length).trim();
if (!s.isEmpty()) {
// add text content as new child
this.item.getChildren().add(new TreeItem<>(new XMLNode(s, true)));
}
}
}
现在您可以在选择处理程序中区分:
treeType.getSelectionModel().selectedItemProperty().addListener((obs, oldSelection, newSelection) -> {
XMLNode node = newSelection.getValue();
if (node.isCharacterData()) {
// ...
}
if (node.isElement()) {
// ...
}
});
如果要突出显示字符节点(或以其他方式显示它们),您只需要一个自定义单元格:
treeType.setCellFactory(tv -> new TreeCell<XMLNode>() {
@Override
protected void updateItem(XMLNode item, boolean empty) {
super.updateItem(item, empty) ;
setStyle("");
if (empty) {
setText("");
} else {
setText(item.toString());
if (item.isCharacterData()) {
setStyle("-fx-background-color: yellow;");
}
}
}
});
这是一个SSCCE:
import java.io.IOException;
import java.io.StringReader;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.stage.Stage;
public class XMLTree extends Application {
private final String xml = "<root>\n" +
" <type_1>\n" +
" <element_1>\n" +
" EndNode\n" +
" </element_1>\n" +
" </type_1>\n" +
" <type_2>\n" +
" <element_2>\n" +
" <test>Endnode</test>\n" +
" <test/>\n" +
" </element_2>\n" +
" </type_2>\n" +
"</root>";
@Override
public void start(Stage primaryStage) throws Exception {
TreeView<XMLNode> treeType = new TreeView<>();
treeType.setRoot(readData(xml));
treeType.setCellFactory(tv -> new TreeCell<XMLNode>() {
@Override
protected void updateItem(XMLNode item, boolean empty) {
super.updateItem(item, empty) ;
setStyle("");
if (empty) {
setText("");
} else {
setText(item.toString());
if (item.isCharacterData()) {
setStyle("-fx-background-color: yellow;");
}
}
}
});
treeType.getSelectionModel().selectedItemProperty().addListener((obs, oldSelection, newSelection) -> {
XMLNode node = newSelection.getValue();
if (node.isCharacterData()) {
System.out.println("Selected characters: "+node);
}
if (node.isElement()) {
System.out.println("Selected element: <"+node+">");
}
});
Scene scene = new Scene(treeType);
primaryStage.setScene(scene);
primaryStage.show();
}
public static TreeItem<XMLNode> readData(String data) throws SAXException, ParserConfigurationException, IOException {
SAXParserFactory parserFactory = SAXParserFactory.newInstance();
SAXParser parser = parserFactory.newSAXParser();
XMLReader reader = parser.getXMLReader();
TreeItemCreationContentHandler contentHandler = new TreeItemCreationContentHandler();
// parse file using the content handler to create a TreeItem representation
reader.setContentHandler(contentHandler);
reader.parse(new InputSource(new StringReader(data)));
// use first child as root (the TreeItem initially created does not contain data from the file)
TreeItem<XMLNode> item = contentHandler.item.getChildren().get(0);
contentHandler.item.getChildren().clear();
return item;
}
public static class TreeItemCreationContentHandler extends DefaultHandler {
public TreeItem<XMLNode> item = new TreeItem<>();
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
this.item = this.item.getParent();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
TreeItem<XMLNode> item = new TreeItem<>(new XMLNode(qName, false));
this.item.getChildren().add(item);
this.item = item;
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
String s = String.valueOf(ch, start, length).trim();
if (!s.isEmpty()) {
// add text content as new child
this.item.getChildren().add(new TreeItem<>(new XMLNode(s, true)));
}
}
}
public static void main(String[] args) {
launch(args);
}
}
注意:我不熟悉DOM类(虽然我使用它们时发现它不是一个非常容易使用的API);因此,可以使用现有的API而不是自定义的XMLNode
类。这应该会给你这个想法。