IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C Discussion :

strcpy struct et xml


Sujet :

C

  1. #1
    Membre confirmé
    Homme Profil pro
    Développeur Web en Loisir
    Inscrit en
    Janvier 2006
    Messages
    129
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web en Loisir

    Informations forums :
    Inscription : Janvier 2006
    Messages : 129
    Par défaut strcpy struct et xml
    bonsoir,

    Je bute sur le problème suivant.
    Avec libxml, je lis un fichier xml sans aucun problème et souhaiterais initialiser une structure avec le résultat. Le programme plante à l'éxécution.

    La ligne avec printf affiche bien la donnée que je veux, elle est donc bien récupérée depuis le fichier xml.
    Si je remplace la ligne strcpy par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    strcpy(waypoints[i].wp_nom, "coco");
    le code s'exécute sans erreur.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    static int nb_wp = 0;
     
    typedef struct
    {
        char wp_nom[5];
        int wp_x;
        int wp_y;
    } s_waypoint;
     
    s_waypoint *waypoints;
     
    void import_wp()
    {
        xmlDoc *doc = xmlReadFile("basic.xml", NULL, 0);
        if (doc == NULL)
        {
           g_print("Le fichier xml n'existe pas.\n");
        } else
        {
            xmlNode *xmlroot = xmlDocGetRootElement(doc)->children;
            xmlNode *current = NULL;
            int i = 0;
     
            for (current=xmlroot; current != NULL; current=current->next)
            {
                if (strcmp((char*)current->name, "targetpoint") == 0)
                {
                    nb_wp++;
                }
            }
            waypoints = malloc(nb_wp*sizeof(s_waypoint));
           for (current=xmlroot; current != NULL; current=current->next)
            {
                printf("%s\n", (const char*) xmlGetProp(current, (const xmlChar*)"label"));
                strcpy(waypoints[i].wp_nom, (const char*) xmlGetProp(current, (const xmlChar*)"label"));
                i++;
            }
     
            xmlFreeDoc(doc);
            xmlCleanupParser();
        }
    }
    Le fichier xml :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    <?xml version="1.0"?>
    <Waypoints>
      <targetpoint x="398" y="470" label="MTL"/>
      <targetpoint x="473" y="288" label="LTP"/>
    </Waypoints>
    Je ne sais plus quoi faire. Un petit peu d'aide serait la bienvenue.
    Merci

  2. #2
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 397
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 397
    Par défaut
    J'ai du mal à voir, mais déjà ça c'est suspect: strcmp((char*)current->name, "targetpoint")Pourquoi un cast est-il nécessaire? Quel est le type de name?
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Membre confirmé
    Homme Profil pro
    Développeur Web en Loisir
    Inscrit en
    Janvier 2006
    Messages
    129
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web en Loisir

    Informations forums :
    Inscription : Janvier 2006
    Messages : 129
    Par défaut
    J'ai repris le code d'un exemple sur internet pour lire un fichier xml.
    current->name est le nom de la balise xml courante (soit ici targetpoint).
    Je ne sais pas quel est le type retourné par xmlGetProp.
    Il faudrait peut-être voir dans la doc de libxml pour savoir pourquoi il faut un cast mais comme je le disais, l'erreur ne vient pas de cette ligne puisque ça compile et s'exécute en modifiant la ligne avec strcpy.

    Si tu veux, je peux poster le code en entier ?

  4. #4
    Membre Expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Par défaut
    Bonjour,

    quand on ne sait plus quoi faire : on utilise un debugger

    Met un breakpoint sur ton printf qui plante et examine tes variables. Ton cuurent sera de type XML_TEXT_NODE, or toi ce que tu veux c'est un XML_ELEMENT_NODE pour pouvoir en récupérer les propriétés éventuelles ... et là tu te dis ... ah ok ... autant j'ai vérifié être sur un XML_ELEMENT_NODE de name "targetpoint" (ou presque ) dans la boucle précédente autant sur la seconde boucle je ne le fais pas. Tu ne vérifie pas non plus l'éventualité où il n'y a aucune propriété ...

    En utilisant DDD (un débugger graphique on obtient la visualisation suivante de tes données) ce sera peut-être plus clair :

    Le current et son next


    Où se trouvent les propriétés et leurs valeurs


    EDIT: la doc est ... pas forcément facilement lisible/navigable mais elle a le mérite d'exister et d'être complète. C'est vrai qu'en général les tutos laissent à désirer aussi (comme beaucoup de projets gnome).
    Mais http://www.xmlsoft.org/html/libxml-tree.html#xmlGetProp précise que la valeur de retour peut être NULL -> c'est donc à vérifier.
    Je n'ai pas souvent utilisé l'interface DOM, faut s'y faire et souvent avec des programmes de test avec pleins d'erreurs La plupart du temps j'ai utilisé l'interface SAX2.

  5. #5
    Membre confirmé
    Homme Profil pro
    Développeur Web en Loisir
    Inscrit en
    Janvier 2006
    Messages
    129
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web en Loisir

    Informations forums :
    Inscription : Janvier 2006
    Messages : 129
    Par défaut
    bonjour,

    Un debugger !! Ca ne m'était même pas venu à l'idée !!! Il est temps de savoir utiliser celui de CodeBlocks.

    autant j'ai vérifié être sur un XML_ELEMENT_NODE de name "targetpoint" (ou presque ) dans la boucle précédente autant sur la seconde boucle je ne le fais pas
    Tu as raison et c'était ça le problème, le debugger m'indiquait 'segmentation fault strcat'. Avec la vérification dans la 2è boucle, y'a plus de pb.

    Merci beaucoup, maintenant je ferais des vérifs systématiques.

    Y'a toujours un autre bug par contre c'est quand je fais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    strcpy(waypoints[i].wp_x, (const char*) xmlGetProp(current, (const xmlChar*)"x"));
    car waypoints[i].wp_x est déclaré de type int donc j'en déduis que je peux pas utiliser strcpy cette fois.

    Comment je fais alors pour initialiser waypoints[i].wp_x ? Y a-t-il une fonction identique strcpy mais pour les int ??

  6. #6
    Membre confirmé
    Homme Profil pro
    Développeur Web en Loisir
    Inscrit en
    Janvier 2006
    Messages
    129
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web en Loisir

    Informations forums :
    Inscription : Janvier 2006
    Messages : 129
    Par défaut
    J'ai compris je peux faire directement

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    waypoints[i].wp_x = (int)xmlGetProp(current, (const xmlChar*)"x");
    pour des int.

    Par contre au lieu de 398, waypoints[0].wp_x contient 27854768 ????
    une idée?

  7. #7
    Membre Expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Par défaut
    C'est normal que tu n'obtiennes pas la bonne valeur. Si on regarde la doc de xmlGetProp :
    Function: xmlGetProp

    xmlChar * xmlGetProp (xmlNodePtr node, const xmlChar * name)

    Search and get the value of an attribute associated to a node This does the entity substitution. This function looks in DTD attribute declaration for #FIXED or default declaration values unless DTD use has been turned off. NOTE: this function acts independently of namespaces associated to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp() for namespace aware processing.

    node: the node
    name: the attribute name
    Returns: the attribute value or NULL if not found. It's up to the caller to free the memory with xmlFree().
    xmlGetProp renvoie un xmlChar* qui est un pointeur sur une chaine de caractères, c'est-à-dire l'adresse de cette chaine.
    Ce que tu fais est de prendre la valeur de cette adresse, ce qui n'est pas ce que tu attends.

    Pour transformer le contenu d'une chaine en nombre tu as à ta disposition les fonctions strtol qui te permet de faire une gestion fine des erreurs, et atoi qui ne fait aucune gestion d'erreur.
    Tu peux par exemple faire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    waypoints[i].wp_x = atoi( xmlGetProp(current, (const xmlChar*)"x") );
    mais c'est une mauvaise façon de faire pour deux raisons:
    • comme je te l'ai déjà dit atoi ne gère pas les erreur. Par exemple si dans ton fichier xml tu as x="en plein milieu" alors atoi te renverra 0 comme si de rien n'était.
    • beaucoup plus grave : la doc spécifie que tu as la charge de libérer ce pointeur = tu dois faire un free dessus. Or utilisée ainsi, tu ne pourras jamais libérer la valeur de retour.


    Une façon parmi d'autres de faire pourrait être :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    char *tmp= (char *)xmlGetProp(current, (const xmlChar*)"x");
    if (tmp != NULL) {
      // ici tmp contient une chaine valide qu'on va essayer d'interpréter
      // comme un nombre en base 10
      char *endptr;
      long valeur=strtol(tmp, &endptr, 10);
      if (*endptr!=0) {
        // cela signifie que la chaine ne contient pas qu'un nombre valide
        // à gérer ...
      } else if ( (valeur<INT_MIN) || (valeur>INT_MAX) ) {
        // il y a bien un nombre mais il est trop grand  pour pouvoir
        // être stocké dans un int
        // à gérer
      } else {
        // ici on est sûr que tmp ne contenait qu'un nombre et qu'il peut être
        // stocké dans un int ... ouf
        waypoints[i].x = (int) valeur;
      }
      // Comme on vient de traiter tmp on peut désormais le libérer
      free(tmp);
    } else {
      // la propriété "x" n'a pas été trouvée
      // à gérer
    }
    code non vérifé ... juste tapé à la volée pour donner une idée. Avec ça tu peut réagir dans chaque cas de figure ...

    Le code suivant est plus simple car aucune gestion d'erreur n'est faite. Si la propriété ne contient autre chose qu'un nombre ou si elle n'est pas présente on obtiendra 0, le code est à tester dans le cas où il y a un nombre trop grand pour pouvoir être représenté.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    tmp=xmlGetProp(current, (const xmlChar*)"x");
    if (tmp != NULL) {
      waypoints[i].x = atoi(tmp);
      free(tmp);
    } else {
      waypoints[i].x = 0;
    }
    code toujours non vérifé et toujours tapé à la volée.

    Références : man page de strtol, de atoi, la doc de xmlGetProp, limits.h.


    Sinon pour l'idée : apprendre le C avec un sujet un peu plus facile La libxml2 n'est pas une mince affaire si on a du mal avec les pointeurs. Profite de DVP et ses cours

  8. #8
    Membre confirmé
    Homme Profil pro
    Développeur Web en Loisir
    Inscrit en
    Janvier 2006
    Messages
    129
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web en Loisir

    Informations forums :
    Inscription : Janvier 2006
    Messages : 129
    Par défaut
    Merci pour toutes tes réponses.

    Effectivement, je devrais peut-être éplucher la stdlib avant d'aller plus loin et approfondir les pointeurs car c'est un gros projet.
    Je l'avais déjà réalisé en javascript avec mootools (pour implémenter la POO) et la lib vectoriel raphael.
    Là j'utilise gtk3 + goocanvas.
    Le C, c'est totalement différent (la compilation, les cast non automatiques, gestion plus stricte des erreurs, des librairies à n'en plus finir, pas de POO...)
    C'est dur !! mais ça sera plus rapide à la fin

    La doc de libxml, heureusement que tu es là pour me la décortiquer parce que sinon....
    J'ai plus qu'à me mettre au boulot et tester tes exemples. (je mettrai résolu après)

    merci encore et bon we

  9. #9
    Membre Expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Par défaut
    Oui, se mettre dans l'optique C peut parfois être ardu.
    En tout cas bon courage et bonne continuation

  10. #10
    Membre confirmé
    Homme Profil pro
    Développeur Web en Loisir
    Inscrit en
    Janvier 2006
    Messages
    129
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web en Loisir

    Informations forums :
    Inscription : Janvier 2006
    Messages : 129
    Par défaut
    Merci

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Balises HTML dans un fichier XML
    Par Bastet79 dans le forum XML/XSL et SOAP
    Réponses: 12
    Dernier message: 04/09/2002, 15h29
  2. delphi XML / HTML caractéres speciaux !
    Par adem dans le forum EDI
    Réponses: 2
    Dernier message: 29/08/2002, 17h48
  3. Débutant XML
    Par viny dans le forum XML/XSL et SOAP
    Réponses: 8
    Dernier message: 25/07/2002, 12h07
  4. Pas de casse dans les XML
    Par :GREG: dans le forum Composants VCL
    Réponses: 4
    Dernier message: 17/07/2002, 13h51
  5. Problème avec [b]struct[/b]
    Par Bouziane Abderraouf dans le forum CORBA
    Réponses: 2
    Dernier message: 17/07/2002, 10h25

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo