Home / Programmazione / Java / Manipolare file XML con Java
Mattepuffo

Manipolare file XML con Java

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.