81 votes

Comment lire et écrire des fichiers XML ?

Je dois lire et écrire à partir et à destination d'un XML dossier. Quel est le moyen le plus simple de lire et d'écrire des fichiers XML en utilisant Java ?

0 votes

Analyse syntaxique partielle de xml efficace en mémoire via StAX : stackoverflow.com/questions/52614082/

137voto

Costis Aivalis Points 8935

Voici un exemple rapide de DOM qui montre comment lire et écrire un simple fichier xml avec son dtd :

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE roles SYSTEM "roles.dtd">
<roles>
    <role1>User</role1>
    <role2>Author</role2>
    <role3>Admin</role3>
    <role4/>
</roles>

et le dtd :

<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT roles (role1,role2,role3,role4)>
<!ELEMENT role1 (#PCDATA)>
<!ELEMENT role2 (#PCDATA)>
<!ELEMENT role3 (#PCDATA)>
<!ELEMENT role4 (#PCDATA)>

Importez-les d'abord :

import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
import org.xml.sax.*;
import org.w3c.dom.*;

Voici quelques variables dont vous aurez besoin :

private String role1 = null;
private String role2 = null;
private String role3 = null;
private String role4 = null;
private ArrayList<String> rolev;

Voici un lecteur (String xml est le nom de votre fichier xml) :

public boolean readXML(String xml) {
        rolev = new ArrayList<String>();
        Document dom;
        // Make an  instance of the DocumentBuilderFactory
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        try {
            // use the factory to take an instance of the document builder
            DocumentBuilder db = dbf.newDocumentBuilder();
            // parse using the builder to get the DOM mapping of the    
            // XML file
            dom = db.parse(xml);

            Element doc = dom.getDocumentElement();

            role1 = getTextValue(role1, doc, "role1");
            if (role1 != null) {
                if (!role1.isEmpty())
                    rolev.add(role1);
            }
            role2 = getTextValue(role2, doc, "role2");
            if (role2 != null) {
                if (!role2.isEmpty())
                    rolev.add(role2);
            }
            role3 = getTextValue(role3, doc, "role3");
            if (role3 != null) {
                if (!role3.isEmpty())
                    rolev.add(role3);
            }
            role4 = getTextValue(role4, doc, "role4");
            if ( role4 != null) {
                if (!role4.isEmpty())
                    rolev.add(role4);
            }
            return true;

        } catch (ParserConfigurationException pce) {
            System.out.println(pce.getMessage());
        } catch (SAXException se) {
            System.out.println(se.getMessage());
        } catch (IOException ioe) {
            System.err.println(ioe.getMessage());
        }

        return false;
    }

Et ici un écrivain :

public void saveToXML(String xml) {
    Document dom;
    Element e = null;

    // instance of a DocumentBuilderFactory
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    try {
        // use factory to get an instance of document builder
        DocumentBuilder db = dbf.newDocumentBuilder();
        // create instance of DOM
        dom = db.newDocument();

        // create the root element
        Element rootEle = dom.createElement("roles");

        // create data elements and place them under root
        e = dom.createElement("role1");
        e.appendChild(dom.createTextNode(role1));
        rootEle.appendChild(e);

        e = dom.createElement("role2");
        e.appendChild(dom.createTextNode(role2));
        rootEle.appendChild(e);

        e = dom.createElement("role3");
        e.appendChild(dom.createTextNode(role3));
        rootEle.appendChild(e);

        e = dom.createElement("role4");
        e.appendChild(dom.createTextNode(role4));
        rootEle.appendChild(e);

        dom.appendChild(rootEle);

        try {
            Transformer tr = TransformerFactory.newInstance().newTransformer();
            tr.setOutputProperty(OutputKeys.INDENT, "yes");
            tr.setOutputProperty(OutputKeys.METHOD, "xml");
            tr.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
            tr.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "roles.dtd");
            tr.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");

            // send DOM to file
            tr.transform(new DOMSource(dom), 
                                 new StreamResult(new FileOutputStream(xml)));

        } catch (TransformerException te) {
            System.out.println(te.getMessage());
        } catch (IOException ioe) {
            System.out.println(ioe.getMessage());
        }
    } catch (ParserConfigurationException pce) {
        System.out.println("UsersXML: Error trying to instantiate DocumentBuilder " + pce);
    }
}

getTextValue est ici :

private String getTextValue(String def, Element doc, String tag) {
    String value = def;
    NodeList nl;
    nl = doc.getElementsByTagName(tag);
    if (nl.getLength() > 0 && nl.item(0).hasChildNodes()) {
        value = nl.item(0).getFirstChild().getNodeValue();
    }
    return value;
}

Ajoutez quelques accesseurs et mutateurs et vous avez terminé !

7 votes

Le fichier dtd est-il nécessaire pour que cela fonctionne ou pouvons-nous lire le xml sans le dtd ? si le dtd est nécessaire, pouvons-nous générer facilement un dtd à partir du xml au lieu de tout taper nous-mêmes ?

3 votes

Vous pouvez laisser le fichier dtd de côté. Assurez-vous que vous éliminez également la référence à celui-ci dans le fichier xml : <!DOCTYPE roles SYSTEM "roles.dtd">. Vous pouvez trouver des applications gratuites de génération de dtd ou utiliser un service en ligne. Ils génèrent un fichier dtd "suffisamment bon" pour commencer. En général, vous devrez le modifier un peu.

0 votes

Superbe exemple ! J'ai eu un petit problème avec la fonction getTextValue(), elle devrait retourner une chaîne de longueur zéro au lieu de null si le noeud est vide. J'ai dû ajouter "if(value==null) value = "" ;" avant le "return value", sinon il y aurait un crash lors de l'écriture de la chaîne XML.

17voto

ran Points 269

Écriture de XML à l'aide de JAXB (Java Architecture for XML Binding) :

http://www.mkyong.com/java/jaxb-hello-world-example/

package com.mkyong.core;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Customer {

    String name;
    int age;
    int id;

    public String getName() {
        return name;
    }

    @XmlElement
    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    @XmlElement
    public void setAge(int age) {
        this.age = age;
    }

    public int getId() {
        return id;
    }

    @XmlAttribute
    public void setId(int id) {
        this.id = id;
    }

} 

package com.mkyong.core;

import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

public class JAXBExample {
    public static void main(String[] args) {

      Customer customer = new Customer();
      customer.setId(100);
      customer.setName("mkyong");
      customer.setAge(29);

      try {

        File file = new File("C:\\file.xml");
        JAXBContext jaxbContext = JAXBContext.newInstance(Customer.class);
        Marshaller jaxbMarshaller = jaxbContext.createMarshaller();

        // output pretty printed
        jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

        jaxbMarshaller.marshal(customer, file);
        jaxbMarshaller.marshal(customer, System.out);

          } catch (JAXBException e) {
        e.printStackTrace();
          }

    }
}

11voto

Diego C Nascimento Points 1303

La réponse ci-dessus ne concerne que l'analyseur DOM (qui lit normalement le fichier entier en mémoire et l'analyse, ce qui est un problème pour un gros fichier), vous pourriez utiliser un analyseur SAX qui utilise moins de mémoire et est plus rapide (de toute façon, cela dépend de votre code).

L'analyseur SAX rappelle certaines fonctions lorsqu'il trouve un début d'élément, une fin d'élément, un attribut, du texte entre les éléments, etc. obtenir ce dont vous avez besoin.

Quelques exemples de code :

http://www.mkyong.com/java/how-to-read-xml-file-in-java-sax-parser/

4voto

Matthias Points 2510

Les réponses ne couvrent que DOM / SAX et une implémentation copier-coller d'un exemple JAXB.

Cependant, il manque un élément important lorsque vous utilisez le XML. Dans de nombreux projets ou programmes, il est nécessaire de stocker ou de récupérer certaines structures de données de base. Votre programme dispose déjà de classes pour vos jolis et brillants objets d'entreprise / structures de données, vous voulez juste un moyen confortable de convertir ces données en une structure XML afin de pouvoir faire plus de magie dessus (stocker, charger, envoyer, manipuler avec XSLT).

C'est là qu'intervient XStream. Il vous suffit d'annoter les classes contenant vos données ou, si vous ne souhaitez pas modifier ces classes, de configurer une instance XStream pour le marshalling (objets -> xml) ou le unmarshalling (xml -> objets).

En interne, XStream utilise la réflexion, les méthodes readObject et readResolve de la sérialisation standard des objets Java.

Vous obtenez un bon et rapide tutoriel ici :

Pour donner un bref aperçu de la façon dont il fonctionne, je fournis également un exemple de code qui marshalle et démarshalle une structure de données. Le marshalling / unmarshalling se passe dans la section main le reste n'est que du code pour générer des objets de test et leur fournir des données. Il est très simple de configurer la méthode xStream et le marshalling / unmarshalling est fait avec une ligne de code chacun.

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import com.thoughtworks.xstream.XStream;

public class XStreamIsGreat {

  public static void main(String[] args) {
    XStream xStream = new XStream();
    xStream.alias("good", Good.class);
    xStream.alias("pRoDuCeR", Producer.class);
    xStream.alias("customer", Customer.class);

    Producer a = new Producer("Apple");
    Producer s = new Producer("Samsung");
    Customer c = new Customer("Someone").add(new Good("S4", 10, new BigDecimal(600), s))
        .add(new Good("S4 mini", 5, new BigDecimal(450), s)).add(new Good("I5S", 3, new BigDecimal(875), a));
    String xml = xStream.toXML(c); // objects -> xml
    System.out.println("Marshalled:\n" + xml);
    Customer unmarshalledCustomer = (Customer)xStream.fromXML(xml); // xml -> objects
  }

  static class Good {
    Producer producer;

    String name;

    int quantity;

    BigDecimal price;

    Good(String name, int quantity, BigDecimal price, Producer p) {
      this.producer = p;
      this.name = name;
      this.quantity = quantity;
      this.price = price;
    }

  }

  static class Producer {
    String name;

    public Producer(String name) {
      this.name = name;
    }
  }

  static class Customer {
    String name;

    public Customer(String name) {
      this.name = name;
    }

    List<Good> stock = new ArrayList<Good>();

    Customer add(Good g) {
      stock.add(g);
      return this;
    }
  }
}

1voto

Cfx Points 2014

Ok, ayant déjà DOM, JaxB et XStream dans la liste des réponses, il y a encore une façon complètement différente de lire et d'écrire le XML : Projection de données Vous pouvez découpler la structure XML et la structure Java en utilisant une bibliothèque qui fournit des vues en lecture et en écriture des données XML sous forme d'interfaces Java. À partir de l'interface tutoriels :

Compte tenu de certains XML du monde réel :

<weatherdata>
  <weather
    ... 
    degreetype="F"
    lat="50.5520210266113" lon="6.24060010910034" 
    searchlocation="Monschau, Stadt Aachen, NW, Germany" 
            ... >
    <current ... skytext="Clear" temperature="46"/>
  </weather>
</weatherdata>

Avec la projection de données, vous pouvez définir une interface de projection :

public interface WeatherData {

@XBRead("/weatherdata/weather/@searchlocation")   
String getLocation();

@XBRead("/weatherdata/weather/current/@temperature")
int getTemperature();

@XBRead("/weatherdata/weather/@degreetype")
String getDegreeType();

@XBRead("/weatherdata/weather/current/@skytext")
String getSkytext();

/**
 * This would be our "sub projection". A structure grouping two attribute
 * values in one object.
 */
interface Coordinates {
    @XBRead("@lon")
    double getLongitude();

    @XBRead("@lat")
    double getLatitude();
}

@XBRead("/weatherdata/weather")
Coordinates getCoordinates();
}

Et utiliser les instances de cette interface tout comme les POJOs :

private void printWeatherData(String location) throws IOException {

final String BaseURL = "http://weather.service.msn.com/find.aspx?outputview=search&weasearchstr=";

// We let the projector fetch the data for us
WeatherData weatherData = new XBProjector().io().url(BaseURL + location).read(WeatherData.class);

// Print some values
System.out.println("The weather in " + weatherData.getLocation() + ":");
System.out.println(weatherData.getSkytext());
System.out.println("Temperature: " + weatherData.getTemperature() + "°"
                                   + weatherData.getDegreeType());

// Access our sub projection
Coordinates coordinates = weatherData.getCoordinates();
System.out.println("The place is located at " + coordinates.getLatitude() + ","
                                              + coordinates.getLongitude());
}

Cela fonctionne même pour la création de XML, les expressions XPath pouvant être écrites.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X