Parser un fichier xml

boualiasma Messages postés 393 Date d'inscription lundi 22 juin 2009 Statut Membre Dernière intervention 23 décembre 2011 - 18 août 2009 à 21:46
boualiasma Messages postés 393 Date d'inscription lundi 22 juin 2009 Statut Membre Dernière intervention 23 décembre 2011 - 24 nov. 2009 à 22:51
Bonsoir,

Je voulais parser mon fichier XML pouyr extraire certaines informations pour les utiliser dans mon programme C.

J'ai trouvé la librairie libxml2 qui est codée en C et qui possède deux méthodes DOM et SAX.

J'ai bien installé libxml2 et j'ai décidé de travailler avec la méthode SAX qui permet de parser des fichiers XML assez grand et n'est pas gourmande en mémoire.

J'ai trouvé des exemples en général et non simples pour un débutant sur le site officiel de libxml2. Ces exemples sont plus pour la méthode DOM. Je ne trouve pas un exemple pour SAX.

- Est ce que il y a quelqu'un qui a rencontré ce type de problème ?

- Pouvez vous me donner un exemple typique pour que j'applique sur mon fichier XML car j'ai besoin des informations qui se trouvent dans le dernier noeud de mon fichier XML ?

Merci.

208 réponses

Renfield Messages postés 17287 Date d'inscription mercredi 2 janvier 2002 Statut Modérateur Dernière intervention 27 septembre 2021 74
3 nov. 2009 à 08:26
Je parle d'un bête tableau, ou une liste chainée, peu importe avec une case pour chacun des fichiers analysés.

typedef struct {
char* filename;
CONCEPT* concept;
struct REF* next;
} FichierXML ;


Relisant le fil, j'ai trouvé:

Mardi 25 août 2009 à 15:04:24
mais si le but est de t'en servir dans ton soft, pourquoi passer par un fichier ? pourquoi ne pas garder ces résultats en mémoire ?


le temps passe, c'est fou !



Renfield - Admin CodeS-SourceS - MVP Visual Basic
0
boualiasma Messages postés 393 Date d'inscription lundi 22 juin 2009 Statut Membre Dernière intervention 23 décembre 2011 5
3 nov. 2009 à 10:14
Bonjour,

'filename' c'est le nom du fichier XML à parser ou bien c'est le fichier qui j'ai le crée et qui contient les valeurs de ?

Je ne voulais pas utiliser des fichiers intermédiaires seulement des fichiers d'entrée qui sont les fichiers XML à parser.
Que proposez vous ?

J'ai trouvé sur le net que le tableau est plus rapide que la liste chainée au niveau accès.
C'est vraie ?

Vous avez dit auparavant :
en gros, tu as déjà tout ce qu'il faut pour savoir lire les infos dans _concepts.

c'est un bête tableau.
chaque cellule de ce tableau représente un <concept> dans ton fichier XML

cette structure permet entre autre de conserver tous les attribute_ref de tes balises


Et voici la structure complète que vous l'avez proposez dans la solution :
typedef struct REF {

char* reference; // la donnée proprement dite

//void* next;      
    struct REF* next; // pointeur vers la reference suivante (ou 0 s'il n'y a plus de donnée) 
}REF;

// Structure décrivant les <Concept>

typedef struct {

char* ID;         // Valeur de l'Id

REF* intent;      // Liste des  de l'

REF* upperCovers; // Liste des <Concept_Ref> de l'

REF* extent;      // Liste des <Object_Ref> de l'<extent>

} CONCEPT ;



D'après vous, on doit sauvegarder les valeurs de dan un tableau ou bien on peut utiliser directement '_concept ' ?


D'autre part on a :
void DisplayConceptInfos(int index, int showExtent, FILE *fp) {
REF* ref; 

// On valide la valeur de l'index

if (index>=0 && index<_countCpt) {

if (showExtent) {

ref = _concepts[index].extent;
 
if (ref) {

while (ref) {

if (ref->reference)

fprintf(fp,"%s ", ref->reference);

ref = ref->next;

}

fprintf(fp,": "); 

}

}



ref = _concepts[index].intent;
if (_concepts[index].extent && ref) {

while (ref) { 

if (ref->reference)

fprintf(fp,"%s ", ref->reference);

ref = ref->next;

} 
 
  fprintf(fp,"\n");	
}
}

}


Je voulais au lieu de sauvegarder ceci dans le fichier de descripteur alors je voulais stocker ces informations dans un tableau car c'est simple et rapide de parcourir après ce tableau. J'ai remarqué que seul la tableau dynamique est adapté à ce cas car on ne sait pas en avance de ce tableau. oui ? ou bien c'est possible d'utiliser un tableau de taille statique ?

Donc, quelle est la modification à faire dans la fonction 'DisplayConceptInfos' ?

Merci.
0
Renfield Messages postés 17287 Date d'inscription mercredi 2 janvier 2002 Statut Modérateur Dernière intervention 27 septembre 2021 74
3 nov. 2009 à 10:51
tabelau plus rapide... pour naviguer dedans, oui, pas pour lce créer, surtout s'il est dynamique.

D'après vous, on doit sauvegarder les valeurs de dan un tableau ou bien on peut utiliser directement '_concept ' ?

ces valeurs y sont déjà ! dans _concepts->intent


Renfield - Admin CodeS-SourceS - MVP Visual Basic
0
boualiasma Messages postés 393 Date d'inscription lundi 22 juin 2009 Statut Membre Dernière intervention 23 décembre 2011 5
3 nov. 2009 à 11:12
C'est possible de passer '_concept' comme un paramètre d'une fonction 'comparaison()' ?
Si oui, Que ce que on met comme type pour '_concept' car je vais le parcourir dans cette fonction ?
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Renfield Messages postés 17287 Date d'inscription mercredi 2 janvier 2002 Statut Modérateur Dernière intervention 27 septembre 2021 74
3 nov. 2009 à 11:42
comment est déclarée cette variable ?

Renfield - Admin CodeS-SourceS - MVP Visual Basic
0
boualiasma Messages postés 393 Date d'inscription lundi 22 juin 2009 Statut Membre Dernière intervention 23 décembre 2011 5
3 nov. 2009 à 13:15
CONCEPT* _concept;
0
Renfield Messages postés 17287 Date d'inscription mercredi 2 janvier 2002 Statut Modérateur Dernière intervention 27 septembre 2021 74
3 nov. 2009 à 13:21
tu as donc ta réponse à
"Que ce que on met comme type pour '_concept'"

Renfield - Admin CodeS-SourceS - MVP Visual Basic
0
boualiasma Messages postés 393 Date d'inscription lundi 22 juin 2009 Statut Membre Dernière intervention 23 décembre 2011 5
3 nov. 2009 à 22:41
Je parle d'un bête tableau, ou une liste chainée, peu importe avec une case pour chacun des fichiers analysés.

typedef struct {
char* filename;
CONCEPT* concept;
struct REF* next;
} FichierXML ;


'filename' c'est le nom du fichier XML à parser ou bien c'est le fichier qui j'ai le crée et qui contient les valeurs de ?
0
Renfield Messages postés 17287 Date d'inscription mercredi 2 janvier 2002 Statut Modérateur Dernière intervention 27 septembre 2021 74
4 nov. 2009 à 09:13

le fichier qui j'ai le crée et qui contient les valeurs de


tu créé encore des fichiers ?

tu bloques des jours sur de telles questions...

J'ai ajouté ce champ parce que je pense que tu voudra a un moment quelconque de ton programme pouvoir identifier le fichier dont sont issus chaque groupe de concepts...

Renfield - Admin CodeS-SourceS - MVP Visual Basic
0
boualiasma Messages postés 393 Date d'inscription lundi 22 juin 2009 Statut Membre Dernière intervention 23 décembre 2011 5
4 nov. 2009 à 23:43
tu créé encore des fichiers ?
non. je parle d'un fichier qui a été crée pour contenir la lsite des concepts.

Maintenant, je voulais lire directement de la memoire sans passer par le fichier.
0
boualiasma Messages postés 393 Date d'inscription lundi 22 juin 2009 Statut Membre Dernière intervention 23 décembre 2011 5
6 nov. 2009 à 08:57
Bonjour,

typedef struct {
char* filename;
CONCEPT* concept;
struct REF* next;
} FichierXML ;


1) C'est à dire que FichierXML est une liste de chainée qui contient comme partie des données le nom de fichier xml 'filename' à parser et la liste des ces concepts 'concept'.
C'est çà ?
2) C'est possible de utiliser un tableau de structure ou lieu de cette liste chainée:

typedef struct {
char* filename;
CONCEPT* concept;
} FichierXML ;

On va allouer ce tableau 'FichierXML' de manière dynamique puisque on sait le nombre de fichier XML à parser.

Mais, je ne sais pas quel est le meilleur choix une liste chainée ou un tableau dynamique ?

3) Dans mon programme principal, le traitement est le suivant:
Pour i de 1 à N Faire
{
- lire le fichier XML
- charger la liste de ces concepts dans un tableau ou un tableau
}

Après la lecture de tous ces fichiers XML et la sauvegarde des concepts dans une structure :liste ou un tableau, je vais travailler avec cette structure par exemple:
- L'affichage les valeurs de intents
de tous les structures déjà chargées
- l'affichage se fait structure par structure:
Pour i de 0 à N-1 Faire
{
afficher le contenu de structure

}

C'est possible de parcourir cette structure par indice qui se trouve dans le boucle ?


Je souhaite que vous m'aidez et je serais très contente pour toute proposition.

Merci.
0
Renfield Messages postés 17287 Date d'inscription mercredi 2 janvier 2002 Statut Modérateur Dernière intervention 27 septembre 2021 74
6 nov. 2009 à 09:44
liste chainée, tableau, fais toi plaisir....
aucune différence.

après, le traitement ne sera que peu changé

Renfield - Admin CodeS-SourceS - MVP Visual Basic
0
boualiasma Messages postés 393 Date d'inscription lundi 22 juin 2009 Statut Membre Dernière intervention 23 décembre 2011 5
18 nov. 2009 à 09:59
Bonjour,

J'ai chargé le contenu des '_concepts ' dans un tableau 'rets

REF* ref=NULL; 
int i,retsize = 0,p;
    char **ret = NULL,result[1024];

lire_fichier("input.lat.xml");
   for (p=0; p <_countCpt; p++)
{
          
ref = _concepts[p].intent;
if (_concepts[p].extent && ref) 
{
strcpy(result,"\0");
  while (ref)
  { 
    
if (ref->reference)
{
strcat(result,ref->reference);
strcat(result," ");
ref = ref->next;
}
  }
  ret = xrealloc(ret, (++retsize) * sizeof(char*)); /* On alloue une case de plus au tableau de string, puis on ajoute la chaine à la fin du tableau */
          ret[retsize-1] = mstrndup(result, strlen(result));
}
      }
     
           
        ret = xrealloc(ret, (++retsize) * sizeof(char*)); /* On ajoute un dernier pointeur sur NULL pour savoir quand le tableau se termine */
        ret[retsize-1] = NULL;
       
    
}


Dans chaque case de tableau 'rets' contient les 'intents' concaténés pour chaque 'extent' non nul
<Extent>
<Object_Ref>40787</Object_Ref>
<Object_Ref>14756</Object_Ref>
<Object_Ref>4771</Object_Ref>
<Object_Ref>4826</Object_Ref>
</Extent>

a
b
cc



la case va contenir la chaine
"a bb cc" mais de plus avec un espace à la fin.

Je vais parcourir ce tableau 'rets' et comparer ces éléments à autres tableaux qui ne contient pas à la fin de chaque case un espace dans ces chaines de caractères.

Comment résoudre ce problème d'espace à la fin ?

Ou bien vous avez autre idée de charger le contenu de '_concepts' dans un tableau ?


Merci.
0
Renfield Messages postés 17287 Date d'inscription mercredi 2 janvier 2002 Statut Modérateur Dernière intervention 27 septembre 2021 74
18 nov. 2009 à 10:26
ben... c'est toi qui le met, cet espace ^^


result[0] = 0;
while (ref)
{ 		    
    if (ref->reference)
    {
        if (result[0])  
            strcat(result," ");
strcat(result,ref->reference);
ref = ref->next;
     }
}


ainsi, l'espace sera ajouté avant l'ajout de la reference, si result n'est pas vide.


Renfield - Admin CodeS-SourceS - MVP Visual Basic
0
boualiasma Messages postés 393 Date d'inscription lundi 22 juin 2009 Statut Membre Dernière intervention 23 décembre 2011 5
19 nov. 2009 à 00:14
Bonjour,
- Que présente pour vous le 'resultat'?
- Est ce que 'strcat' ajoute un espace entre les deux mots automatiquement?

- Je ne comprends votre solution:
result[0] = 0;
while (ref)
{ 		    
    if (ref->reference)
    {
        if (result[0])  
            strcat(result," ");
strcat(result,ref->reference);
ref = ref->next;
     }
}



Est ce que cette solution permet de charger les valeurs de 'intent' non nuls pour chaque 'extent' non nul dans une case de tableau comme une chaine de caractère ?

Mon but est d'obtenir un tableau où chaque case contenant les valeurs de 'intent' correspondant ni espace à la fin seulement on a l'espace entre les valeurs de 'intent'

par exemple, si on :
<Extent>
<Object_Ref>40787</Object_Ref>
<Object_Ref>14756</Object_Ref>
<Object_Ref>4771</Object_Ref>
<Object_Ref>4826</Object_Ref>
</Extent>

a
b
cc




Alors la case de tableau contient la chaine:
"a b cc"

Avez vous une solution ?

Merci.
0
Renfield Messages postés 17287 Date d'inscription mercredi 2 janvier 2002 Statut Modérateur Dernière intervention 27 septembre 2021 74
19 nov. 2009 à 07:57
je t'ai filé le code a mettre en remplacement de :

		strcpy(result,"\0");
  while (ref)
  { 
    
if (ref->reference)
{
strcat(result,ref->reference);
strcat(result," ");
ref = ref->next;
}
  }


tout simplement !

Renfield - Admin CodeS-SourceS - MVP Visual Basic
0
boualiasma Messages postés 393 Date d'inscription lundi 22 juin 2009 Statut Membre Dernière intervention 23 décembre 2011 5
19 nov. 2009 à 09:36
Bonjour,

Mais il va rester un espace à la fin.
Je vais obtenir par exemple "a b cc " au lieu "a b cc"

et si je compare après "a b cc " et "a b cc" alors elles ne sont pas la même chose alors en réalité elles sont les mêmes.

Comment résoudre ce problème ?

Merci.
0
Renfield Messages postés 17287 Date d'inscription mercredi 2 janvier 2002 Statut Modérateur Dernière intervention 27 septembre 2021 74
19 nov. 2009 à 09:39
"Mais il va rester un espace à la fin. "

Pour quelle raison ?

On vide la chaine 'result'

on parcoure chaque element, afin de remplir la chaine 'result'
si la chaine 'result' est non vide, on ajoute un espace
on y ajoute la reference
on continue la boucle

ainsi, tant que la reference est non vide... on n'ajoute pas d'espace sans rien derriere

Renfield - Admin CodeS-SourceS - MVP Visual Basic
0
boualiasma Messages postés 393 Date d'inscription lundi 22 juin 2009 Statut Membre Dernière intervention 23 décembre 2011 5
19 nov. 2009 à 09:55
On fait comme çà:
lire_fichier("input.lat.xml");
   for (p=0; p <_countCpt; p++)
{
          
ref = _concepts[p].intent;
if (_concepts[p].extent && ref) 
{
result[0] = 0;
while (ref)
{ 		    
    if (ref->reference)
    {
        if (result[0])  
            strcat(result," ");
strcat(result,ref->reference);
ref = ref->next;
     }
}

}

}


C'est juste ?

C'est quoi result[0] = 0 ?
est ce que on met un 0 comme un caractère dans 'result' qui est une chaine de caractère ?


Est ce 'strcat' ajoute un espace par défaut ?


Merci.
0
Renfield Messages postés 17287 Date d'inscription mercredi 2 janvier 2002 Statut Modérateur Dernière intervention 27 septembre 2021 74
19 nov. 2009 à 10:09
pas le caractère "0" mais le caractère de code ascii zero : l'indicateur de fin de chaine.

Est ce 'strcat' ajoute un espace par défaut ?


pas compris la question.


tu ne mets plus cette partie ???
		  ret = xrealloc(ret, (++retsize) * sizeof(char*)); /* On alloue une case de plus au tableau de string, puis on ajoute la chaine à la fin du tableau */
          ret[retsize-1] = mstrndup(result, strlen(result));
}
      }
     
           
        ret = xrealloc(ret, (++retsize) * sizeof(char*)); /* On ajoute un dernier pointeur sur NULL pour savoir quand le tableau se termine */
        ret[retsize-1] = NULL;
       
    
}



Renfield - Admin CodeS-SourceS - MVP Visual Basic
0
Rejoignez-nous