Netbeans: How to populate JTree Dynamically? - java

I am developing a small desktop application in Java using NetBeans. At some point i need to read data from XML file and after reading that i need to store that in object of my custom class. I sucessfully did the above mentioned task (i.e I read XML data and store that data in object of my custom class). Now i want to populate a JTree with that object. Suppose my XML looks like this:
<Employees>
<Classification type="permanent">
<Emp>
<name>Emp1_Name<name/>
</Emp>
<Emp>
<name>Emp2_Name<name/>
</Emp> </Classification>
<Classification type="part time">
<Emp>
<name>Emp1_Name<name/>
</Emp>
<Emp>
<name>Emp2_Name<name/>
</Emp> </Classification>
</Classification>
</Employees>
Now i want my tree to look like this
Employees
Permanent Employees
Emp1_Name
Emp2_Name
Part Time Employees
Emp1_Name
Emp2_Name

This might be useful for you :
http://www.arsitech.com/xml/jdom_xml_jtree.php
http://www.wsoftware.de/SpeedJG/XMLTreeView.html
Code Taken From :
Java: How to display an XML file in a JTree
public JTree build(String pathToXml) throws Exception {
SAXReader reader = new SAXReader();
Document doc = reader.read(pathToXml);
return new JTree(build(doc.getRootElement()));
}
public DefaultMutableTreeNode build(Element e) {
DefaultMutableTreeNode result = new DefaultMutableTreeNode(e.getText());
for(Object o : e.elements()) {
Element child = (Element) o;
result.add(build(child));
}
return result;
}

You need to write the function to fetch the information of your application object, You can use SAX or DOM parser for that
DefaultMutableTreeNode root = new DefaultMutableTreeNode()
Object object = //function to fetch the information of your Object
// if you are storing all objects in a vector then read element of object
root.add((DefaultMutableTreeNode)object)

Related

Adding sub-element to element java (DOM)

Essentially, i'm creating an XML document from a file (a database), and then i'm comparing another parsed XML file (with updated information) to the original database, then writing the new information into the database.
I'm using java's org.w3c.dom.
After lots of struggling, i decided to just create a new Document object and will write from there from the oldDocument and newDocument ones i'm comparing the elements in.
The XML doc is in the following format:
<Log>
<File name="something.c">
<Warning file="something.c" line="101" column="23"/>
<Warning file="something.c" line="505" column="71" />
</File>
</Log>
as an example.
How would i go about adding in a new "warning" Element to the "File" without getting the pesky "org.w3c.dom.DOMException: WRONG_DOCUMENT_ERR: A node is used in a different document than the one that created it." exception?
Cutting it down, I have something similar to:
public static Document update(Element databaseRoot, Element newRoot){
Document doc = db.newDocument(); // DocumentBuilder defined previously
Element baseRoot = doc.createElement("Log");
//for each file i have:
Element newFileRoot = doc.createElement("File");
//some for loop that parses through each 'file' and looks at the warnings
//when i come to a new warning to add to the Document:
NodeList newWarnings = newFileToCompare.getChildNodes(); //newFileToCompare comes from the newRoot element
for (int m = 0; m < newWarnings.getLength(); m++){
if(newWarnings.item(m).getNodeType() == Node.ELEMENT_NODE){
Element newWarning = (Element)newWarnings.item(m);
Element newWarningRoot = (Element)newWarning.cloneNode(false);
newFileRoot.appendChild(doc.importNode(newWarningRoot,true)); // this is what crashes
}
}
// for new files i have this which works:
newFileRoot = (Element)newFiles.item(i).cloneNode(true);
baseRoot.appendChild(doc.importNode(newFileRoot,true));
doc.appendChild(baseRoot);
return doc;
}
Any ideas? I'm beating my head against the wall. First time doing this.
Going through with a debugger I verified that the document owners were correct. Using node.getOwnerDocument(), I realized that the newFileRoot was connected to the wrong document earlier when I created it, so I changed
Element newFileRoot = (Element)pastFileToFind.cloneNode(false);
to
Element newFileRoot = (Element)doc.importNode(pastFileToFind.cloneNode(false),true);
since later on when i was trying to add the newWarningRoot to newFileRoot, they had different Documents (newWarningRoot was correct but newFileRoot was connected to the wrong document)

How to recursively get the elements and its children from an XML?

I need to build a tree view of the elements present in an XML file.
For example,
<abc>
<abcd/>
<abcd/>
</abc>
<def>
<defg/>
<jkl/>
<defg/>
</def>
My TreeView should look like this:
>abc
>abcd
>abcd
>def
>defg
>jkl
>defg
>def
I need to read the elements and build a treeView in JavaFX. I'm not sure which data structure to use here. If I use List> to store <(node, children)>, each child can have multiple children and they can have many and so on. So, I'm not able to figure out what data structure to use. Can anyone suggest what is the possible way here?
UPDATE:
Using the reference in this Java: How to display an XML file in a JTree , I tried doing like this in JavaFX.
public TreeView<String> build(String pathToXml) throws Exception {
SAXReader reader = new SAXReader();
Document doc = (Document) reader.read(pathToXml);
return new TreeView<String>(build(doc.getRootElement()));
}
public TreeItem<String> build(Element e) {
TreeItem<String> item = new TreeItem<String>(e.getText());
for(Object o : e.elements()) {
Element child = (Element) o;
item.getChildren().add(build(child));
}
return item;
}
But I'm not able to see the content in TreeView. When I debugged, e.getText() is having only "\n\n". Is there a way to handle it? Am I doing this correctly?

Matching string to xml data

I pulled two strings from a user input. I need to match one of them to the row ID.
I'm unaware of whether or not I would need to parse the Strings into integers (Perhaps even parse all of my XML data into strings, then look up that data) or if I can use the Strings to directly lookup XML data? Perhaps neither.
Here's an example of what i'm storing in my XML file:
<?xml version="1.0" encoding="UTF-8"?>
<data>
<language>
<row id="7101">
<language-from>English</language-from>
<language-to>Thai</language-to>
<cost>30.00</cost>
<comment><![CDATA[out source]]></comment>
</row>
</language>
</data>
Looking at the XML document, I suggest you parse the XML document to a set of structured objects, store them in a map for easy lookup, where the key is your search criteria that comes from the user's input. Unless the XML file changes too often, one-time parsing of the document is worth it than any string based searches on it.
I would define a class to hold that information as follows:
class TranslationCost
{
private int id;
private String sourceLang;
private String targetLang;
private float cost;
private String comment;
}
Map<Integer, TranslationCost> idTocostMap;
public float calculateCost(int id, int countOfWords)
{
TranslationCost costObj = idToCostMap.get(id);
if (null == costObj) {
// throw exception
}
return costObj.getCost() * countOfWords;
}
something like that...
You could use xPath query to look up the nodes...
Document xmlDoc = // Load the XML into an DOM document
Node root = xmlDoc.getDocumentElement();
XPathFactory xFactory = XPathFactory.newInstance();
XPath xPath = getXPathFactory().newXPath();
XPathExpression xExpress = getXPath().compile("/data/language/row[language-from='English']");
NodeList nodeList = (NodeList)xExpress.evaluate(root, XPathConstants.NODESET);
I'd personally build a simpler model around the concept to make it easier to call into, but the concept is the same

Inserting a node in an xml file

I would like to insert a node in an xml file using Java DOM. I am actually editing a lot of contents of a dummy file in order to mofidy it like the original.
I would want to add an open node and close node in between the following file;
<?xml version="1.0" encoding="utf-8"?>
<Memory xmlns:xyz="http://www.w3.org/2001/XMLSchema-instance"
xmlns:abc="http://www.w3.org/2001/XMLSchema" Derivative="ABC"
xmlns="http://..">
///////////<Address> ///////////(which I would like to insert)
<Block ---------
--------
-------
/>
////////// </Address> /////////(which I would like to insert)
<Parameters Thread ="yyyy" />
</Memory>
I hereby request you to let me know how to I insert -- in between the xml file?
Thanks in advance.!
What I have tried doing is;
Element child = doc.createElement("Address");
child.appendChild(doc.createTextNode("Block"));
root.appendChild(child);
But this gives me an output like;
<Address> Block </Address> and not the way i expect :(
And now, what I have tried is to add these lines;
Element cd = doc.createElement("Address");
Node Block = root.getFirstChild().getNextSibling();
cd.appendChild(Block);
root.insertBefore(cd, root.getFirstChild());
But still, this is not the output which i am looking for. I got this output as
---------
What you want is probably:
Node parent = block.getParentNode()
Node blockRemoved = parent.removeChild(block);
// Create address
parent.appendChild(address);
address.appendChild(blockRemoved);
This is the standard way to re-attach a node in another place under W3C DOM.
Here:
DocumentBuilder b = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document document = b.parse(...);
// Parent of existing Block elements and new Address elemet
// Might be retrieved differently depending on
// actual structure
Element parent = document.getDocumentElement();
Element address = document.createElement("address");
NodeList nl = parent.getElementsByTagName("Block");
for (int i = 0; i < nl.getLength(); ++i) {
Element block = (Element) nl.item(i);
if (i == 0)
parent.insertBefore(address, block);
parent.removeChild(block);
address.appendChild(block);
}
// UPDATE: how to pretty print
LSSerializer serializer =
((DOMImplementationLS)document.getImplementation()).createLSSerializer();
serializer.getDomConfig().setParameter("format-pretty-print", Boolean.TRUE);
LSOutput output =
((DOMImplementationLS)document.getImplementation()).createLSOutput();
output.setByteStream(System.out);
serializer.write(document, output);
I assume you are using the W3C DOM (e.g. http://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html ). If so try
insertBefore(address, block);

Adding a new node before the first child in dom tree

This is probably one of those easiest things to deal with but for some reason not working for me. I'm trying to add a new node after the root in dom tree.
Here's the original string:
<div class="discussionThread dt"><div class="dt_subject">2011 IS HERE!</div></div>
I'm trying to add a new node which is in the form of a string before . The final version should look like:
<div class="discussionThread dt"><div class="test">Test Val</div><div class="dt_subject">2011 IS HERE!</div></div>
As you can see, the new Test Val is being added immediately after the root div class. I've used few methods to place the node at the right place but its getting appended at the end.
Here's a sample which I referred from one of the earlier posts:
String newNode = "<div class="test">test</div>";
SAXReader reader = new SAXReader();
Document newNodeDocument = reader.read(new StringReader(newNode));
Document originalDoc = new SAXReader().read(new StringReader(content));
Element root = originalDoc.getRootElement();
Element givenNode = originalDoc.getRootElement();
givenNode.add(newNodeDocument.getRootElement());
This is resulting the node getting added at the end. I tried using insertBefore(), but didn't work out.
Any pointers will be highly appreciated.
Thanks
Why create a new Document or a new root Element? I think the shortest way is using Branch#content:
Returns the content nodes of this
branch as a backed List so that
the content of this branch may be
modified directly using the interface.
The List is backed by the Branch so
that changes to the list are reflected
in the branch and vice versa.
You just have to create the new Element and to add it to the root element through the List provided by content method (passing it the position index), this is my main:
public static void main(String[] args) throws DocumentException {
SAXReader reader = new SAXReader();
String xml = "<div class=\"discussionThread dt\"><div class=\"dt_subject\">2011 IS HERE!</div></div>";
Document document = reader.read(new StringReader(xml));
DefaultElement newElement = new DefaultElement("div");
newElement.addAttribute("class", "test");
newElement.add(new DefaultText("Test Val"));
List content = document.getRootElement().content();
if (content != null ) {
content.add(0, newElement);
}
System.out.println(document.asXML());
}
which prints out the following xml:
<div class="discussionThread dt"><div class="test">Test Val</div><div class="dt_subject">2011 IS HERE!</div></div>
In addition, you should also consider the use of xslt when you have to transform xml.
You're calling Element#add(Entity). From the Javadocs:
Adds the given Entity to this element. If the given node already has a parent defined then an IllegalAddException will be thrown.
So the new node you're adding will be added as a child of the node you're adding it to. You cannot add another node after the root node you have, because a document can have only one root node.
What you can do is create a new root node, then add the old root node and the new node as children of this new root node. Then set the root node of the document to the new root node.
Why not just create a new Document with the value you want, then append the other nodes to it?

Categories