Parser un fichier xml

Signaler
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
-
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
-
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

Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
J'ai trois fichiers xml à lire et à manipuler .

D'après le le résultat de débogage précédent que proposez vous ?

Merci.
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
Où on ajoute exactement:

_currentCpt = -1;

dans la fonction suivante 'cleanup()':

void cleanup()

{

int i;

REF* ref;

for (i=0; i<_countCpt; i++) {

// On libère donc une a une les zones mémoire allouées

free(_concepts[i].ID);



// On néttoie ensuite les listes chainées, une à une.

ref = _concepts[i].intent;

while (ref) {

free(ref->reference);

ref = ref->next;

}



ref = _concepts[i].upperCovers;

while (ref) {

free(ref->reference);

ref = ref->next;

}



ref = _concepts[i].extent;

while (ref) {

free(ref->reference);

ref = ref->next;

}

}

// Avant de désallouer le tableau de Concepts

free(_concepts);

}



Cette solution est valable quelque soit le nombre de fichier à manipuler ?
Merci.
Messages postés
17286
Date d'inscription
mercredi 2 janvier 2002
Statut
Modérateur
Dernière intervention
23 décembre 2019
69
à la fin, peu importe : on ne se sert pas de cette variable dans cette procédure, pas de risque, donc.


et valable quel que soit le nombre de fichiers : on se remet en situation initiale (sauf les flags _inExtent etc. mais pas grave)


Renfield - Admin CodeS-SourceS - MVP Visual Basic
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
Merci infiniment çà marche pour 3 fichiers pour 4.

Supposons que on a des dizaines de fichiers et on applique cette solution que vous avez m'aider pour résoudre ce problème de début jusqu'à la fin:

- Est que on aura pas de problème de débordement mémoire ou bien problème allocation et de libération ?

- Est ce que on peut optimiser notre solution au niveau temps d'exécution le moins possible?

- Comment savoir c'est le problème est dû au problème de mémoire et que le programme se plante à un certain moment?

- Est ce que vous avez fixé dans une partie de la solution une taille d'une variable ou structure et si on dépasse cette solution alors la solution ne sera pas valable ou bien vous avez supposé un format bien défini d'une telle donnée au autre ?

- C'est à dire la solution finale est passe par tout quelque soit le nombre des fichiers xml, le nombre de concepts, le type de 'extent', le type de 'intent' etc ou bien des restrictions?

J'ai remarqué que dans la fonction 'characters' au dessous il y a la valeur 32. Cette valeur est fixé par vous ou bien vous avez récupéré ?

void characters(void* user_data, const xmlChar *ch, int len) {

if (_inID && len) {

// On va enregistrer l'ID, mais en supprimant les espaces qui semblent s'être introduits  5 

while(len>1 && *ch==32) {

len--;

ch+=sizeof(xmlChar);

}



// On supprime également les espaces qui suivent la valeur.

while(len>1 && *(ch+len-1)==32)

len--;



_concepts[_currentCpt].ID = (char*)malloc(len+1);

strncpy(_concepts[_currentCpt].ID, ch, len);

*(_concepts[_currentCpt].ID+len) = 0;

_inID = 0;

}

else if ((_inIntent || _inUpperCovers || _inExtent) && len)

{	

// lien vers les references du concept courant

REF** source;

REF* ref;

REF* newRef;



if (_inIntent)

source = &(_concepts[_currentCpt].intent);

else if (_inUpperCovers)

source = &(_concepts[_currentCpt].upperCovers);

else if (_inExtent)

source = &(_concepts[_currentCpt].extent);



ref = *source;



// on créé une nouvelle reference

newRef = (REF*)calloc(1, sizeof(REF));



// permet de relier la nouvelle reference a la structure (liste chainee)

if (ref) {

// La liste contient au moins une cellule.

// On va parcourir la liste a la recherche de la dernière cellule (celle qui à le pointeur next à NULL)

while(ref->next)

ref = (REF*)ref->next;

ref->next = newRef;

}

else

*source = newRef; // Première cellule de la liste chainée



// on recopie la donnée

newRef->reference = (char*)malloc(len+1);

strncpy(newRef->reference, ch, len);

// 0 terminal de la chaine de caractères

*(newRef->reference+len) = 0;	



// Remise à 0 des flags de position

_inIntent _inUpperCovers _inExtent = 0;

}

}





Merci.
Messages postés
17286
Date d'inscription
mercredi 2 janvier 2002
Statut
Modérateur
Dernière intervention
23 décembre 2019
69
32 => code ascii du caractère espace.

en effet, tes fichier contiennent des espaces avant après l'ID :

5

si je ne veux que le 5, me faut supprimer ces espaces.


Renfield - Admin CodeS-SourceS - MVP Visual Basic
Messages postés
17286
Date d'inscription
mercredi 2 janvier 2002
Statut
Modérateur
Dernière intervention
23 décembre 2019
69
concernant le reste, tuot est dynamique, fonction de ce qui est lu.


Renfield - Admin CodeS-SourceS - MVP Visual Basic
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
Bonsoir,
Oui.C'est Bon.
Merci beaucoup pour vos aides et votre gentillesse.

Je m'excuse si je vous dérange par ma demande suivante
Je vous explique ma demande :
J'ai un fichier nommé "resultat.txt" contenant deux champs de type chaine de caractère: numero et son attribut.
Soit le fichier "resultat.txt":
5 : dd cc aaa
8 : aaa bb dd
10 : bb cc aaa
4 : dd bb cc


Chaque mot formant le deuxième champ(attribut) présente le nom d'un fichier texte.
Dans notre exemple on a les fichiers textes suivants:
"dd.txt", "cc.txt", "aaa.txt" et "bb.txt".
On peut avoir plus ou moins de ces fichiers textes car ceci dépend des mots formant le deuxième champ (attribut).
Le contenu de ces fichiers existent et ils sont générés dans mon programme. chacun de ces fichiers est formant de deux champs: valeur(de type entier) et degree(de type réel).

Dans cet exemple, on a le contenu :
- de fichier "dd.txt" :
257 0.860000
233 1.000000
144 0.880000
377 0.000000
257 0.860000
562 0.000000
456 0.000000
388 0.660000
644 0.000000
277 0.460000



- de fichier "cc.txt" :
160 1.000000
155 1.000000
160 1.000000
155 1.000000
175 0.000000
185 0.000000
170 0.000000
175 0.000000
174 0.000000
163 0.400000


- de fichier "aaa.txt" :
30 1.000000
32 1.000000
45 1.000000
56 1.000000
46 0.860000
48 0.000000
34 0.000000
38 0.500000
59 0.660000
30 0.000000


- de fichier "bb.txt" :
257 0.860000
233 1.000000
144 0.880000
377 0.000000
257 0.860000
562 0.000000
456 0.000000
388 0.660000
644 0.000000
277 0.460000


Je voulais pour chaque numero (premier champ de fichier "resultat.txt") positionner sur la même ligne numéro 'numero' pour chaque fichier txt correspondant et calculer le minimum entre ces valeurs de 'degree'
ppar exemple pour le numero 10 de fichier "resultat.txt" nous allons positionner sur la ligne numéro 10 en même temps pour tous les fichiers correspondant à ce numéro.
Pour cet exemple, on va positionner sur la ligne numéro 10 du fichiers "cc.txt", "aaa.txt" et "bb.txt"
puis on cherche le minimum entre les valeurs de 'degree'
Dans notre exemple, on cherche le minimum entre
0.400000 et 0.000000 et 0.460000

Donc on a le minimum est 0.000000

Et donc on souhaite obtenir le résultat final qui va être stocker dans un fichier nommée "resultat_final" est :

5 : dd cc aaa : 0.00
8 : aaa bb dd : 0.00
10 : bb cc aaa : 0.00
4 : dd bb cc : 0.00



Je n'oublierai pas vos aides car la solution de ma dernière demande signifie fin de mon travail.

Je souhaite que vous acceptez cette demande et me répondez.

Que proposez vous ?

Merci.
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
Bonjour,

Je n'arrive pas à résoudre ce problème .

Que proposez vous comme solution à ce problème ?

Je vous souhaite que vous m'aidez car la solution sera une fonction à intégrer dans mon programme et donc ce n'est pas le but final.

Merci.
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
Bonsoir,

Je serais très contente si vous m'aidez.

Merci.
Messages postés
17286
Date d'inscription
mercredi 2 janvier 2002
Statut
Modérateur
Dernière intervention
23 décembre 2019
69
ok ok, au bout d'une semaine tu ne semble pas avoir avancé...

je m'y colle, je reviens vers toi dans la journée

faudrait vraiment te mettre à bosser, non ?


Renfield - Admin CodeS-SourceS - MVP Visual Basic
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
Bonjour,
Merci beaucoup.
Oui c'est vraie vous êtes raison.

La solution pour ma dernière demande présente
une fonction à intégrer dans mon programme.

Je vous souhaite que vous m'aidez.
Messages postés
17286
Date d'inscription
mercredi 2 janvier 2002
Statut
Modérateur
Dernière intervention
23 décembre 2019
69
#include <stdlib.h>
#include <stdio.h>

int readInt(FILE* fp, int *ret)
{
int i;
char sBuffer[32];
for (i=0;i<8;i++)
{
sBuffer[i] = fgetc(fp);
if (sBuffer[i]==32)
{
sBuffer[i] = 0;
*ret = strtol(sBuffer, NULL, 0);
return 0;
}
}

*ret = 0;
return -1;
}

double LireDegree(int nLineNumber, char* sFileName)
{
char sBuffer[32];
FILE* fp;
int i=0;

if (fp = fopen(sFileName, "r")) {
while(--nLineNumber)
while (!feof(fp) && fgetc(fp)!=10);
while (fgetc(fp)!=32);
while(!feof(fp)) {
sBuffer[i] = fgetc(fp);
if (sBuffer[i]==32 || sBuffer[i]==13)
break;
i++;
}
sBuffer[i] = 0;
fclose(fp);
return strtod(sBuffer, NULL);
}
return 0.0;
}

int main()
{
char sBuffer[32];
FILE *fp, *fp_final;
int nLineNumber, i;
double nCurDegree, nMinDegree = 0.0;
int bFirst=1;
int bBreak = 0;

fp = fopen("resultat.txt", "r");
fp_final = fopen("resultat_final.txt", "w");
while (!readInt(fp, &nLineNumber)) {
fprintf(fp_final, "%d :", nLineNumber);
fgetc(fp);
i=0;
while(!feof(fp)) {
sBuffer[i]=fgetc(fp);
if (sBuffer[0]==10)
break;
else if (sBuffer[i]==10 || sBuffer[i]==32 && i!=0) {
bBreak = (sBuffer[i]==10);

sBuffer[i] = 0;
fprintf(fp_final, " %s", sBuffer);

sBuffer[i++] = '.';
sBuffer[i++] = 't';
sBuffer[i++] = 'x';
sBuffer[i++] = 't';
sBuffer[i] = '\0';

nCurDegree = LireDegree(nLineNumber, sBuffer);
if (nMinDegree>nCurDegree || bFirst) 
{
bFirst = 0;
nMinDegree = nCurDegree;
}
i=0;
if (bBreak)
break;
}
else if (sBuffer[0]!=32)
i++;
}
fprintf(fp_final, " : %f\n", nMinDegree);
bFirst = 1;
}
fclose(fp);
fclose(fp_final);

system("type resultat_final.txt");
system("pause");
}


Renfield - Admin CodeS-SourceS - MVP Visual Basic
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
Bonjour,

Merci beaucoup.

Tout d'abord votre solution donne:


5 : dd cc aaa : 0.000000
8 : aaa bb dd : 0.500000
10 : bb cc aaa : 0.000000
4 : dd bb : 0.000000


Cette résultat obtenue si les différents fichiers ("aaa.txt", "bb.txt", "cc.txt", "dd.txt")textes décrites au dessus ils ont un seul espace entre les deux champs formant chaque fichier.

Mais le résultat souhaité est :
5 : dd cc aaa : 0.00
8 : aaa bb dd : 0.50
10 : bb cc aaa : 0.00
4 : dd bb cc : 0.00


Dans votre résultat, vous obtenez :
4 : dd bb


Mais elle vous manque 'cc'
Or on doit obtenir:
4 : dd bb cc



Or si les différents fichiers ("aaa.txt", "bb.txt", "cc.txt", "dd.txt")textes décrites au dessus ils ont plusieurs espaces pas un seul espace entre les deux champs formant chaque fichier alors je n'obtiens le bon résultat puisque tous les minimum sont égales à 0.000000

Quelles sont les modifications à faire dans votre solution ?


Quels sont les fichiers et leurs formats avec lesquels vous avez testé la solution ?

car pour les différents fichiers ("aaa.txt", "bb.txt", "cc.txt", "dd.txt")textes décrites au dessus ils ont plusieurs espaces pas un seul espace entre les deux champs formant chaque fichier. De plus ces fichiers sont générés automatiquement dans le programme.
En réalité, je fais
fprintf(fp,"%10d%s\n",champ1,champ2)
Je dois travailler avec ce format.

C'est possible que vous me commenter la solution pour comprendre mieux ?

Merci.
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
Bonsoir,

La solution pour ma dernière demande présente
une fonction à intégrer dans mon programme.

Je vous souhaite que vous m'aidez.

Merci.
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
Bonjour,

Je suis bloquée à ce niveau. La solution à la dernière demande me manque pour l'intégrer dans mon projet final.
S'il vous plait, qu'est ce qu'il manque cette solution pour répondre à la dernière demande ?

Je tiens compte pour vos aides et je n'oublierai pas vos efforts.

Merci.
Messages postés
17286
Date d'inscription
mercredi 2 janvier 2002
Statut
Modérateur
Dernière intervention
23 décembre 2019
69
Mais c'est pas possible, ça !
Tu reste bloquée deux semaines comme ça, sans problème, toi ?

y'a juste à corriger et faire :

else if (feof(fp) || sBuffer[i]==10 || sBuffer[i]==32 && i!=0) {

au lieu de

else if (sBuffer[i]==10 || sBuffer[i]==32 && i!=0) {

et hop, le dernier fichier désigné est pris en compte....


concernant le nombre d'espaces, tu remarqueras (ou aurais pu remarquer) qu'il m'importe peu, que je les supprime tous.

"je n'oublierai pas vos efforts. "
Pense plutot aux tiens.


Renfield - Admin CodeS-SourceS - MVP Visual Basic
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
Bonjour,

Merci beaucoup çà marche.

J'ai quelques points non clairs et je voulais que vous me les expliquez:

sBuffer[i]==10 || sBuffer[i]==32


Que présentent 10 et 32 ?
Est ce que ces sont de taille maximale de deux champs ?

Dans mon travail, on peut avoir un fichier qui dépasse les 10 lignes et la taille de deuxième champ peut dépasser les 32 caractères.

comment nous allons résoudre ce problème ?


Ce résultat obtenue si les différents fichiers ("aaa.txt", "bb.txt", "cc.txt", "dd.txt")textes décrites au dessus ils ont un seul espace entre les deux champs formant chaque fichier.

Or si les différents fichiers ("aaa.txt", "bb.txt", "cc.txt", "dd.txt")textes décrites au dessus ils ont plusieurs espaces pas un seul espace entre les deux champs formant chaque fichier alors je n'obtiens le bon résultat souhaité puisque tous les minimum sont égales à 0.000000

Quelles sont les modifications à faire dans votre solution ?


Quels sont les fichiers et leurs formats avec lesquels vous avez testé la solution ?

car pour les différents fichiers ("aaa.txt", "bb.txt", "cc.txt", "dd.txt")textes décrites au dessus ils ont plusieurs espaces pas un seul espace entre les deux champs formant chaque fichier. De plus ces fichiers sont générés automatiquement dans mon programme.
En réalité, je fais
fprintf(fp,"%10d%s\n",champ1,champ2)
Je dois travailler avec ce format.


C'est possible que vous me commenter la solution pour comprendre mieux ?

Merci.
Messages postés
17286
Date d'inscription
mercredi 2 janvier 2002
Statut
Modérateur
Dernière intervention
23 décembre 2019
69
sBuffer est un tableau de caractères...
sBuffer[i] représente le caractère que l'on viens de lire.

cela ne peut donc etre la longueur d'un champ quelconque...

10 représente un saut de ligne
32 un espace

ca permet de détecter la fin du nom du fichier a analyser...

Il me parait étrange d'avoir tantôt un espace, tantot deux... pas très 'normal', ça...
"Quelles sont les modifications à faire dans votre solution ? "
et toi, as tu pensé a la solution a apporter ?

j'ai utilisé les fichiers que tu m'a transmis...


Renfield - Admin CodeS-SourceS - MVP Visual Basic
Messages postés
17286
Date d'inscription
mercredi 2 janvier 2002
Statut
Modérateur
Dernière intervention
23 décembre 2019
69
commenter davantage ?
y'a même pas 100 lignes de code..... m'enfin

Renfield - Admin CodeS-SourceS - MVP Visual Basic
Messages postés
17286
Date d'inscription
mercredi 2 janvier 2002
Statut
Modérateur
Dernière intervention
23 décembre 2019
69
pour l'espace que tu t'amuse a mettre en plusieurs exemplaire, suffit de corriger LireDegree :

while(!feof(fp)) {
sBuffer[i] = fgetc(fp);
if (i && sBuffer[i]==32 || sBuffer[i]==13)
break;
if (sBuffer[i]!=32)
i++;
}


Renfield - Admin CodeS-SourceS - MVP Visual Basic