Fichier XML

Expression du besoin

De nombreuses applications ont un besoin d’un format standard pour échanger et distribuer des données. Le langage XML répond à ses besoins et il s’est imposé comme format de référence pour l’échange de données.

XML

XML signifie eXtensible Markup Language (Langage de balisage extensible).

Le langage est standardisé par la spécification W3C XML 1.0 du 10/02/98.

Lien : cours XML

Un document XML bien formé signifie que le texte XML obéit aux règles syntaxiques de XML. Le document considéré comme valide (facultatif) signifie que le texte XML est bien formé et répond à une structure définie par une DTD (Definition Type Document).

Remarque : XML n’est pas un langage de programmation mais de description de document.

Les avantages d’XML sont nombreux :

  • Lisibilité : aucune connaissance ne doit théoriquement être nécessaire pour comprendre un contenu d’un document XML (il est autodescriptif et extensible)
  • Adaptabilité : sa structure arborescente permet de modéliser la majorité des problèmes informatiques 
  • Universalité et portabilité : fichier texte ASCII avec le support de l’encodage UNICODE 
  • Déployable : facilement distribué par n’importe quels protocoles capables de transporter du texte (comme HTTP)
  • Exensibilité : ce métalangage le rend utilisable dans tous les domaines d’applications

Un document XML est structuré en trois parties :

  • un prologue : qui indique la version XML utilisée, le jeu de caractères (encoding) et la présence d’une DTD (standalone).
  • des instructions de traitement (IT) ou “processing instruction” (PI) : instructions relatives à des applications qui traiteront le document (feuille de style, transformation, …)
  • l’arbre des éléments : le contenu du document

Remarque : par ailleurs, une feuille XML peut contenir des commentaires de la même manière qu’un document HTML.

Un document XML est composé d’éléments désignés par des balises et structuré sous la forme d’un arbre avec un et un seul élément racine (root).

Remarque : Les éléments sont aussi appelés noeuds ou nodes (par référence à la théorie des graphes).

Un prologue contient systématiquement une déclaration qui spécifie la version de XML utilisée : <?xml version="1.0" ?>. Il existe également deux autres attributs : encoding (pour définir le type de codage du jeu de caractères) et standalone (pour préciser si une DTD est utilisée avec no).

De plus en plus de logiciels utilisent le format XML (Extensible Markup Language) pour leurs fichiers de données (Microsoft Office, LibreOffice/OpenOffice, …).

Remarque : ils existent pour l’échange de données des formats anciennement répandus comme le format CSV (voir l’activité sur les fichiers CSV) et les fichiers INI (voir l’activité sur les fichiers INI).

API Qt

Qt fournit un module QtXml qu’il faut activer dans son fichier de projet .pro :

...
QT += xml
...

Dans ce module, Qt fournit de nombreuses classes qui permettent de gérer des documents XML :

La classe de base modélisant un document XML est QDomDocument :

Objectifs

Être capable de lire et écrire des données dans un fichier XML.

Séquence 1 : lire un fichier XML

On va créer une application GUI qui permet de gérer une liste d’interfaces USB. La description de ces interfaces est stockée dans le fichier interfaces.xml qui est lu au démarrage de l’application et afficher dans une liste déroulante. On pourra supprimer une interface ou ajouter une interface et le fichier XML sera mis à jour.

Le fichier interfaces.xml est le suivant :

<?xml version="1.0" encoding="UTF-8"?>
<interfaces>
  <interface id="0">
    <peripherique>/dev/ttyUSB0</peripherique>
  </interface>
  <interface id="1">
    <peripherique>/dev/ttyUSB1</peripherique>
  </interface>
</interfaces>

Pour manipuler ces interfaces dans le programme, on définira cette structure de données :

typedef struct
{
    int      id;
    QString  peripherique;

} Interface;

La première tâche est de lire un fichier XML lorsqu’on démarre l’application afin d’afficher les interfaces disponibles dans la liste déroulante.

Pour cela, on utilisera la méthode lireXML() :

bool MaFenetre::lireXML()
{
    // Le fichier XML
    QFile fichierXML(INTERFACES_XML);

    if(!(fichierXML.open(QIODevice::ReadOnly)))
    {
        QMessageBox::critical(0,"Erreur","Le fichier XML n'a pas pu être ouvert !");
        return false;
    }
    else
    {
        QDomDocument documentXML;

        documentXML.setContent(&fichierXML, false);
        QDomElement racine = documentXML.documentElement(); // <interfaces>
        if(racine.isNull())
        {
            qDebug() << "<MaFenetre::lireXML()> erreur racine !";
            return false;
        }

        QDomNode noeudInterface = racine.firstChild();
        if(noeudInterface.isNull())
        {
            qDebug() << "<MaFenetre::lireXML()> erreur racine vide !";
            return false;
        }

        while(!noeudInterface.isNull())
        {
            Interface interface;
            QDomElement elementInterface = noeudInterface.toElement(); // <interface>
            if(elementInterface.isNull())
            {
                qDebug() << "<MaFenetre::lireXML()> erreur element interface !";
                break;
            }

            QDomNode noeudPeripherique = elementInterface.firstChild();
            if(!noeudPeripherique.isNull())
            {
                QDomElement elementPeripherique = noeudPeripherique.toElement(); // <peripherique>

                interface.id = elementInterface.attribute("id").toInt(); // l'id
                interface.peripherique = elementPeripherique.text(); // le device
                interfaces.push_back(interface);
            }
            else qDebug() << "<MaFenetre::lireXML()> erreur noeud peripherique !";

            noeudInterface = noeudInterface.nextSibling();
        }

        fichierXML.close();
    }

    return true;
}

Code source complet : test-mo-fichier-xml.zip

Séquence 2 : écrire dans un fichier XML

La méthode ecrireXML() qui réaliser l’écriture dans le fichier XML lorsqu’on supprime une interface ou qu’on en ajoute une dans la liste :

bool MaFenetre::ecrireXML()
{
    // Le fichier XML
    QFile fichierXML(INTERFACES_XML);
    //QFile fichierXML("test.xml");

    if(!(fichierXML.open(QIODevice::ReadWrite | QIODevice::Truncate)))
    {
        QMessageBox::critical(0,"Erreur","Erreur ouverture fichier XML !");
        return false;
    }
    else
    {
        QDomDocument documentXML;

        documentXML.setContent(&fichierXML, false);
        QDomNode xmlNode = documentXML.createProcessingInstruction("xml","version=\"1.0\" encoding=\"UTF-8\"");
        documentXML.insertBefore(xmlNode, documentXML.firstChild());

        if(interfaces.size() > 0)
        {
            QDomElement root = documentXML.createElement("interfaces");
            documentXML.appendChild(root);

            for(int i = 0; i < interfaces.size(); i++)
            {
                QDomElement elementInterface = documentXML.createElement("interface");
                elementInterface.setAttribute("id", interfaces[i].id);
                root.appendChild(elementInterface);

                QDomElement elementPeripherique = documentXML.createElement("peripherique");
                elementInterface.appendChild(elementPeripherique);

                QDomText text = documentXML.createTextNode(interfaces[i].peripherique);
                elementPeripherique.appendChild(text);
            }
        }

        QTextStream out(&fichierXML);
        documentXML.save(out, 2);

        fichierXML.close();
    }

    return true;
}

Code source complet : test-mo-fichier-xml.zip

Séquence 3 : valider un document XML

Pour vérifier si le document interfaces-dtd.xml est « valide », on peut utiliser tout d’abord un outil local (xmllint, nsgmls ou rxp) puis un outil distant (http://validator.w3.org/check ou voir les URLs fournis dans le cours). 

Exemple si on oublie l’attribut id dans un élément interface :

$ xmllint -valid interfaces-dtd.xml
interfaces-dtd.xml:6: element interface: validity error : 
Element interface does not carry attribute id
...

Avec la DTD suivante :

<!ELEMENT interfaces (interface+)>
<!ELEMENT interface (peripherique)>
<!ATTLIST interface id CDATA #REQUIRED>
<!ELEMENT peripherique (#PCDATA)>

Fichiers d’exemple : test-mo-fichier-xml.zip

Retour au sommaire