Analyse de données stockées dans un texte formaté en XML

Michel SIMATIC, Loïc JOLY et Amina GUERMOUCHE

12 mai 2023

1 Introduction

Le but de cet exercice est :

  1. d’analyser les données stockées dans un texte formaté selon un format XML, ce texte pouvant être stocké dans un fichier ou dans une chaîne de caractères d’un programme,
  2. d’automatiser les tests vérifiant que l’analyse est correcte.

A la fin de cet exercice, vous serez capable d’analyser un texte comme celui-ci :

        <?xml version = "1.0"?>
        <Group label="testGroup" x="0" y="1">
             <Circle label="testCircle1" x="2" y="3" r="4" color="Black"/>
             <Circle label="testCircle2" x="5" y="6" r="7" color="Black"/>
        </Group>

qui spécifie :

NB : Pour simplifier cet exercice, nous nous contenterons de stocker dans une std::string (et non dans un fichier) les octets du texte au format XML.

Par ailleurs, à la fin de cet exercice, vous aurez automatisé vos tests avec Google Test.

2 Création du projet

3 Codage de la lecture d’un Circle

Nous souhaitons être en mesure de lire le XML suivant :

        <?xml version = "1.0"?>
        <Circle label="testCircle" x="0" y="1" r="2" color="Black"/>
        #include <string>
        std::string sc = R"(<?xml version = "1.0"?>
                            <Circle label="testCircle" x="0" y="1" r="2" color="Black" />)";
        pugi::xml_document doc;
        pugi::xml_parse_result result = doc.load_string(sc.c_str());
        if (!result) {
            std::cerr << result.description();
            exit(1);
        } 
        pugi::xml_node node = doc.child("Circle");
        #include <iostream>
        using namespace std;
Circle "testCircle", x: 0, y: 1, r: 2, color: "Black"

4 Codage de la lecture d’un Group

Procédez de la même manière que précédemment pour lire le XML suivant :

        <?xml version = "1.0"?>
        <Group label="testGroup" x="0" y="1">
          <Circle label="testCircle1" x="2" y="3" r="4" color="Black"/>
          <Circle label="testCircle2" x="5" y="6" r="7" color="Black"/>
        </Group>

et obtenir l’affichage suivant :

Group "testGroup", x: 0, y: 1, children: [
Circle "testCircle1", x: 2, y: 3, r: 4, color: "Black"
Circle "testCircle2", x: 5, y: 6, r: 7, color: "Black"
]

NB : Pour traiter tous les enfants Circle de votre Group, inspirez-vous d’un exemple de boucle dans la documentation pugixml (Cherchez cet exemple de boucle en cherchant le mot children dans cette documentation).

Dans l’affichage précédent du Group "testGroup", les Circle testCircle1 et testCircle2 ne sont pas indentés par rapport au Group testGroup dont ils font partie : On comprend moins bien qu’ils en font partie. Modifiez votre code pour ajouter une indentation et obtenir :

Group "testGroup", x: 0, y: 1, children: [
| Circle "testCircle1", x: 2, y: 3, r: 4, color: "Black"
| Circle "testCircle2", x: 5, y: 6, r: 7, color: "Black"
]

5 Automatisation de vos tests

       if (!result) {
            cerr << result.description();
            exit(1);
        }
        ASSERT_TRUE(result) << result.description(); // Si jamais result est faux, indique que le test est faux *et* 
                                                     // affiche la string result.description() (qui contient la raison 
                                                     // de l'erreur)
        unitTests.cpp(22): error: Expected equality of these values:
          c.dump()
            Which is: "Circle \"testCircle\", x: 0, y: 1, r: 2, color: \"Black\"\n"
          c_dump_ref
            Which is: "Circle \"testCircle\", x: 0, y: 1, r: 2, color: \"Orange\"\n"
        unitTests.cpp(53): error: Expected equality of these values:
          g.dump()
            Which is: "Group \"testGroup\", x: 0, y: 1, children: [\n| Circle \"testCircle1\", x: 2, y: 3, r: 4, color:         \"Black\"\n| Circle \"testCircle2\", x: 5, y: 6, r: 7, color: \"Black\"\n]\n"
          g_dump_ref
            Which is: "Group \"testGroup\", x: 0, y: 1, children: [\n| Circle \"testCircle1\", x: 2, y: 3, r: 4, color:         \"Orange\"\n| Circle \"testCircle2\", x: 5, y: 6, r: 7, color: \"Black\"\n]\n"
        With diff:
        @@ -1,4 +1,4 @@
         Group \"testGroup\", x: 0, y: 1, children: [
        -| Circle \"testCircle1\", x: 2, y: 3, r: 4, color: \"Black\"
        +| Circle \"testCircle1\", x: 2, y: 3, r: 4, color: \"Orange\"
         | Circle \"testCircle2\", x: 5, y: 6, r: 7, color: \"Black\"
         ]\n

Corrigé (à exploiter selon la procédure cmake de ce document).

6 Conclusion

L’automatisation des tests facilite beaucoup la vie des développeur·ses.

C’est pourquoi, dans la suite des TPs, en général (cf. exercices sur les polynômes et sur l’outil de visualisation), nous commencerons par écrire des tests, puis réaliserons l’implémentation afin que ces tests soient corrects (Démarche TDD = Test Driven Development).

Et, c’est seulement après coup que nous nous préoccuperons des éventuels affichages faits par le programme.