Partage
  • Partager sur Facebook
  • Partager sur Twitter

Lire un XML et classer les infos proprement

    15 octobre 2018 à 12:04:44

    Bonjour a tous,

    J'ai pas mal de problème avec un projet.

    Le sujet : Je dois calculer le meilleurs initeraire pour me deplacer dans Sydney. On me donne une fichier xml de cette forme :

    <Station>
        <Name>Bondi Junction</Name>
        <Line>EasternSuburbsIllawarraLine</Line>
        <StationEdges>
           <StationEdge>
               <Name>Edgecliff</Name>
               <Line>EasternSuburbsIllawarraLine</Line>
               <Duration>3</Duration>
            </StationEdge>
          </StationEdges>
       </Station>
    <Station>
       <Name>Edgecliff</Name>
       <Line>EasternSuburbsIllawarraLine</Line>
       <StationEdges>
          <StationEdge>
             <Name>Bondi Junction</Name>
             <Line>EasternSuburbsIllawarraLine</Line>
             <Duration>3</Duration>
          </StationEdge>
          <StationEdge>
             <Name>Kings Cross</Name>
             <Line>EasternSuburbsIllawarraLine</Line>
             <Duration>3</Duration>
          </StationEdge>
       </StationEdges>
    </Station>

    J'ai mis que deux Station de metro mais j'en ai 250 comme ca. On peut donc lire le nom de la station, la ligne et les voisins de cette station ainsi que le temps pour s'y rendre.

    Première étape j'aimerai trouver un moyen de lire le fichier XML de manière assez simple. J'ai regardé beaucoup de site et de tuto mais je n'ai pas trouvé comment faire.
    Je ne sais coder que en C et C# et c'est mon premier projet en C++ du coup je suis un peu perdu avec le melange des classes et des pointeurs ect..

    Pour l'instant ce que j'ai reussi a faire c'est trouver un moyen de lire le XML ligne par ligne et donc de prendre les infos qui m'interesse de cette maniere :

    locName = ligne.find("<Name>");
    if (locName>=0)
         name=ligne.substr(14,ligne.length()-7);
    Idem pour les autres valeurs. Mais le code est tres moche et a la fin je galere et mettre toutes mes valeurs dans mes classes qui sont : 
    class station
    {
    public:
    station(std::string name, std::string line,stationEdge* liste);
    ~station();
    private:
    std::string m_name;
    std::string m_line;
    stationEdge* m_stations;
    };
    et 
    class stationEdge
    {
    public:
    stationEdge();
    stationEdge(std::string name, std::string line,std::string duration);
    ~stationEdge();
    private:
    std::string m_name;
    std::string m_line;
    std::string m_duration;
    };
    Voila c'est tres mal expliqué pour corroner le tout haha

    Mais du coup juste si quelqu'un a un moyen plus simple de lire un XML cela pourrait m'aider ;)
    Merci

    -
    Edité par BrunoBernard4 15 octobre 2018 à 12:10:17

    • Partager sur Facebook
    • Partager sur Twitter
      15 octobre 2018 à 12:09:18

      Pourquoi n'utilises tu pas une lib de XML ? https://en.cppreference.com/w/cpp/links/libs#XML ou une lib generique comme boost ou POCO.

      Comme tu as appris le C avant le C++, tu fais l'erreur d'ecrire du code C dans ton code C++, ce qui est tres problematique (malloc, pointeur nu). Il faut que tu apprennes a oublier ce que tu as appris en C.

      • Partager sur Facebook
      • Partager sur Twitter
        15 octobre 2018 à 12:35:43

        Bonjour,
        Merci de ta reponse
        J'ai installé libxml++ et tinyxml mais une fois le dossier installé je n'ai pas trouvé de tutoriel pour l'utiliser dans mon code. Ou mettre le dossier et comment utiliser la libraire.
        J'ai vraiment l'impression de repartir a zero avec ce language c'est assez frustrant haha
        • Partager sur Facebook
        • Partager sur Twitter
          15 octobre 2018 à 14:41:50

          BrunoBernard4 a écrit:

          J'ai installé libxml++ et tinyxml mais une fois le dossier installé je n'ai pas trouvé de tutoriel pour l'utiliser dans mon code. Ou mettre le dossier et comment utiliser la libraire.

          libxml je connaît pas.

          Tinyxml, de mémoire, c'est des fichiers à ajouter au projet, rajouter les includes puis free-to-go (pour la version light / facile / xml pour les nuls ou les feignants - ce n'est pas un défaut, c'est une qualité - ).

          Tu dois aussi avoir moyen de faire ça plus proprement (avec le .lib à linker via ton IDE - peu importe où tu met tes dossiers : tu spécifieras le chemin vers ces même dossiers)

          Sinon, je trouve le property_tree de boost super clair et assez simple de prise en main. Il faut simplement prendre le temps de bien analyser la doc.

          Ca te permet déjà de lire par "intitulé de balise" et d'éviter une batterie de substr tout cracra sur chaque ligne.

          -
          Edité par LilyKianii 15 octobre 2018 à 14:49:00

          • Partager sur Facebook
          • Partager sur Twitter
            15 octobre 2018 à 14:48:12

            J'aime bien XSD de CodeSynthesis (https://www.codesynthesis.com/products/xsd/). Mais il faut partir d'un schéma XSD -- mais bon quitte à faire du XML, autant y aller à fond, non?
            • Partager sur Facebook
            • Partager sur Twitter
            C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
              15 octobre 2018 à 18:49:48

              Pour des xml simples, tu as rapidxml (c'est la lib qui est utilisée en interne par boost::property_tree), qui présente l'avantage d'être ultra légère (2 hpp, elle header only), ultra rapide et n'a aucune dépendance.
              • Partager sur Facebook
              • Partager sur Twitter
              Mettre à jour le MinGW Gcc sur Code::Blocks. Du code qui n'existe pas ne contient pas de bug
                16 octobre 2018 à 5:02:46

                Merci a tous pour vos reponses j'ai reussi a me depatouiller pour acceder au valeur du XML mais j'ai un autre problème surement du a fait que je suis pas très familier avec le C++

                J'ai donc crée une classe StationEdge de cette maniere 

                class stationEdge
                {
                public:
                	stationEdge();
                	stationEdge(std::string name, std::string line,std::string duration);
                	~stationEdge();
                
                	private:
                	std::string m_name;
                	std::string m_line;
                	std::string m_duration;	
                };

                et une classe station :

                class station
                {
                public:
                		
                	station(std::string name, std::string line,stationEdge* liste);
                	~station();
                	
                	private:
                	std::string m_name;
                	std::string m_line;
                	stationEdge* m_stations;
                };

                Ce que j'essai de faire c'est de créer un tableau de station et chaque station a un tableau de StationEdge.


                Et le ou je m'y perd c'est la difference entre tableau, pointeur, liste etc Le quel serait le plus efficace
                Sachant que le tableau de stationEdge que je fourni a Station n'aura pas la meme taille a chaque fois
                Une station peut avoir 2,3 ou meme 6 stations voisines

                je sais pas si j'ai été très clair dans mes explications mais merci beaucoup :) 


                • Partager sur Facebook
                • Partager sur Twitter
                  16 octobre 2018 à 6:49:56

                  Je verrais plus quelque chose dans ce genre:
                  struct Edge
                  {
                     int station_{};
                     int duration_{};
                  };
                  
                  struct Station
                  {
                     int station_{};
                     std::vector<Edge> edges_{};
                  };
                  
                  using TransportMap = std::vector<Station>;

                  D'abord ça va être beaucoup plus léger en mémoire, et comme tu ne manipules plus que des int, les recherches et les comparaisons seront beaucoup plus rapides. Tout le problème va être de produire ça à partir du xml.

                  Pour cela on va produire 2 tables de correspondances, une pour les lignes et une pour les stations. Il nous faut d'abord être en mesure d'attribuer à chaque ligne et à chaque station un n° unique:

                  class UidGenerator
                  {
                     int seed_{};
                  
                  public:
                  
                     int next() noexecpt {return ++seed_;}
                  
                  };

                  La table des lignes:

                  struct LineIdent
                  {
                     int id_{};
                     std::string name_{};
                  };
                  
                  class LineTable
                  {
                     UidGenerator generate_{};
                     std::vector<LineIdent> lines_{};
                  
                  public:
                  
                     int add(std::string const & name);
                  
                     LineIdent const & find(int id) const;
                  
                  };
                  
                  

                  La table des stations, bâtie exactement sur le même modèle:

                  struct StationIdent
                  {
                     int id_{};
                     int line_{};
                     std::string name_{};
                  };
                  
                  class StationTable
                  {
                     UidGenerator generate_{};
                     std::vector<StationIdent> stations_{};
                  
                  public:
                  
                     int add(std::string const & name,int line);
                     StationIdent const & find(int id) const;
                  };

                  La fonction add permet de créer une nouvelle ligne(respectivement station), si la ligne/station existe déjà dans la table elle renverra l'id créé précédemment.

                  int LineTable::add(std::string const & name)
                  {
                      for (auto const & li : lines_){
                         if (li.name_ == name){
                            return li.id_;
                         }
                      }
                      auto ident = generate_.next();
                      lines_.emplace_back(ident,name);
                      return ident;
                  };

                  La fonction find permet de retrouver une Ligne(respectivement une station) à partir de sont identifiant unique.

                  LineIdent const & LineTable::find(int id) const
                  {
                     for(auto const & li : lines_){
                        if (li.id_ == id) return li;
                     }  
                     assert(false && "Invalid line ident"); 
                  }



                  Lorsque tu parses ton xml tu ajoutes les lignes et les stations au fur et à mesure que tu les découvres. A la sortie tu as ta LineTable, ta StationTable et ta TransportMap. C'est plus simple tu n'as que des vector de structures simples, pas de pointeurs, pas de gestion scabreuse de la mémoire.

                  -
                  Edité par int21h 16 octobre 2018 à 6:55:27

                  • Partager sur Facebook
                  • Partager sur Twitter
                  Mettre à jour le MinGW Gcc sur Code::Blocks. Du code qui n'existe pas ne contient pas de bug
                    16 octobre 2018 à 8:37:06

                    Woaw ! Tres jolie :o

                    J'essai ca :)
                    Merci
                    • Partager sur Facebook
                    • Partager sur Twitter

                    Lire un XML et classer les infos proprement

                    × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                    × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                    • Editeur
                    • Markdown