Manipolare file XML con Java
Java ha varie librerie per manipolare file XML.
La più utilizzata è JDom, ma nell'esempio che vi posto ho usato la libreria standard che va più che bene per piccole cose.
Vi spiegherò anche come caricare i vari nodi dentro a una JList.
La classe XML ha tre metodi:
- create
- read
- save
Il primo serve per creare un file di inizio, e lo richiamo nell'evento WindowOpened.
Il file xml che creeremo è molto semplice:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<todos>
<todo>cast classe personale book java</todo>
</todos>
Una semplice lista di cose da fare.
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class Xml {
private static File xmlFile = new File("todo.xml");
public static void create() throws ParserConfigurationException, TransformerConfigurationException, TransformerException, IOException {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.newDocument();
Element todos = doc.createElement("todos");
doc.appendChild(todos);
Element todo = doc.createElement("todo");
todo.appendChild(doc.createTextNode("Da fare 1"));
todos.appendChild(todo);
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
if (!xmlFile.exists()) {
xmlFile.createNewFile();
StreamResult result = new StreamResult(xmlFile);
transformer.transform(source, result);
}
}
........
//altri metodi
}
Con DocumentBuilderFactory, DocumentBuilder e Document creiamo un documento in formato xml.
Element rappresenta un nodo del DOM.
Ne abbiamo due: todos che è il nodo radice, e un todo che rappresenta le cose da fare; in fututro aggiungerete ed elimenerete i vari do todo.
Con TransformerFactory e Transformer rendiamo l'input adeguato alla struttura xml.
Infine controlliamo se il file già esiste; se non esiste lo creiamo aggiungengo il nodo radice (todos) e un nodo figlio (todo).
A questo punto aggiungiamo il metodo read che restituisce il contenuto sotto forma di ArrayList; il contenuto verrà caricato dentro una JList in avvio di programma:
......... // sempre nella classe XML, sotto al metodo create()
public static ArrayList<ToDo> read() throws ParserConfigurationException, SAXException, IOException {
ArrayList<ToDo> list = new ArrayList<ToDo>();
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(xmlFile);
doc.getDocumentElement().normalize();
NodeList nList = doc.getElementsByTagName("todo");
for (int i = 0; i < nList.getLength(); i++) {
ToDo td = new ToDo(nList.item(i).getTextContent());
list.add(td);
}
return list;
}
Come vedete l'ArrayList come generico usa una classe personalizzata:
public class ToDo {
private String todo;
public ToDo(String todo) {
this.todo = todo;
}
@Override
public String toString() {
return todo;
}
public void setTodo(String to) {
to = this.todo;
}
}
Niente di speciale, era solo per farlo ben formato.
Analiziamo il metodo read.
Prima carichiamo e normaliziamo il file xml (con in vari Document*).
Con NodeList cerchiamo il nodo todo; per ogni nodo trovato aggiungiamo una voce alla lista ArrayList.
A questo punto vediamo l'evento WindowOpened:
private DefaultListModel model = null;
.......
private void formWindowOpened(java.awt.event.WindowEvent evt) {
try {
Xml.create();
ArrayList<ToDo> list = Xml.read();
for (Object obj : list) {
model.addElement(new ToDo(obj.toString()));
}
} catch (TransformerConfigurationException ex) {
JOptionPane.showMessageDialog(null, ex.getMessage());
} catch (TransformerException ex) {
JOptionPane.showMessageDialog(null, ex.getMessage());
} catch (ParserConfigurationException ex) {
JOptionPane.showMessageDialog(null, ex.getMessage());
} catch (SAXException ex) {
JOptionPane.showMessageDialog(null, ex.getMessage());
} catch (IOException ex) {
JOptionPane.showMessageDialog(null, ex.getMessage());
}
}
Prima viene richiamato il metodo create per creare, eventualmente, il file xml in questione.
Poi il metodo read che carica nel DefaultListModel le varie voci dell'ArrayList.
A questo punto per aggiungere e rimuovere elementi agiremo sul'lArrayList, e poi quando vogliamo salviamo il tutto sovrascrivendo il file originale.
Senza spiegarvi le operazioni di aggiunta/rimozione di elementi da una lista, vediamo il metodo save e come viene richiamato:
public static void save(ArrayList<String> list) throws ParserConfigurationException, TransformerConfigurationException, IOException, TransformerException {
if (xmlFile.exists()) {
xmlFile.delete();
}
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.newDocument();
Element todos = doc.createElement("todos");
doc.appendChild(todos);
for (Object obj : list) {
Element todo = doc.createElement("todo");
todo.appendChild(doc.createTextNode(obj.toString()));
todos.appendChild(todo);
}
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
if (!xmlFile.exists()) {
xmlFile.createNewFile();
StreamResult result = new StreamResult(xmlFile);
transformer.transform(source, result);
}
}
Molto simile al metodo create, però in questo caso i nodi li aggiungerà prendendoli da un ArrayList.
In verità questo non è il modo migliore perchè in pratica io cancello il file originale e poi lo ricreo da zero.
Il fatto è che non sono riuscito ad aggiungere nodi al file originale prendendo solo in nuovi valori dall'ArrayList.
Coumunque così funziona abbastanza bene.
Questo invece è lìevento sul pulsante Save che richiama questo metodo:
private void btnSaveActionPerformed(java.awt.event.ActionEvent evt) {
ArrayList<String> newList = new ArrayList<String>();
try {
for (int i = 0; i < model.getSize(); i++) {
newList.add(model.getElementAt(i).toString());
}
Xml.save(newList);
JOptionPane.showMessageDialog(null, "Salvato!");
} catch (IOException ex) {
JOptionPane.showMessageDialog(null, ex.getMessage());
} catch (ParserConfigurationException ex) {
JOptionPane.showMessageDialog(null, ex.getMessage());
} catch (TransformerConfigurationException ex) {
JOptionPane.showMessageDialog(null, ex.getMessage());
} catch (TransformerException ex) {
JOptionPane.showMessageDialog(null, ex.getMessage());
}
}
Riempio un nuovo ArrayList con le voci prese dal DefaultListModel e le passo al metodo.
java xml jlist element nodelist arraylist
Commentami!