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
17288
Date d'inscription
mercredi 2 janvier 2002
Statut
Modérateur
Dernière intervention
27 septembre 2021
70
Allez, je te commente le tout...

j'espere que tu va bien lire et analyser ce qui a été fait.

#include <stdlib.h>
#include <stdio.h>

// Utilisé pour lire le n° de ligne
int readInt(FILE* fp, int *ret)
{
int i;
char sBuffer[32];
// on ne lira pas plus 8 caractères
for (i=0;i<8;i++)
{
sBuffer[i] = fgetc(fp);
if (sBuffer[i]==32) // On est tombé sur l'espace qui suit le N°
{
sBuffer[i] = 0;
*ret = strtol(sBuffer, NULL, 0);
return 0;
}
}

*ret = 0;
return -1;
}

// Permet de lire la valeur double stockée à la ligne désignée, dans le fichier désigné
double LireDegree(int nLineNumber, char* sFileName)
{
// On ne lira pas de montant de plus de 32 caractères
char sBuffer[32];
FILE* fp;
int i=0;

if (fp = fopen(sFileName, "r")) {
// On se place sur la ligne désirée
while(--nLineNumber)
while (!feof(fp) && fgetc(fp)!=10);
// On ne tiens pas compte de la premiere valeur de la ligne
while (fgetc(fp)!=32);
while(!feof(fp)) {
// Et on stocke la donnée, caractère par caractère
sBuffer[i] = fgetc(fp);
// En stoppant dès que l'on trouve un espace ou un saut de ligne après la valeur
if (i && sBuffer[i]==32 || sBuffer[i]==13)
break;
// Et en supprimant tout espace avant la donnée
if (sBuffer[i]!=32)
i++;
}
sBuffer[i] = 0;
fclose(fp);
return strtod(sBuffer, NULL);
}
return 0.0;
}

int main()
{
char sBuffer[32];    // Longeur max supposée d'un nom de fichier
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");
// On lit le numéro de ligne a considérer
while (!readInt(fp, &nLineNumber)) {
fprintf(fp_final, "%d :", nLineNumber);
fgetc(fp); // on lit les deux points séparateurs
i=0;
while(!feof(fp)) {
// On lit le reste, caractère par caractère
sBuffer[i]=fgetc(fp);
if (sBuffer[0]==10) // la dernière ligne du fichier est une ligne vide... on sort
break;
// fin de ligne, ou espace délimitant deux noms de fichier...
else if (feof(fp) || sBuffer[i]==10 || sBuffer[i]==32 && i!=0) {
// était on a une fin de ligne, ou a un espace ?
bBreak = (sBuffer[i]==10);

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

// On ajoute ".txt" au nom obtenu
sBuffer[i++] = '.';
sBuffer[i++] = 't';
sBuffer[i++] = 'x';
sBuffer[i++] = 't';
sBuffer[i] = '\0';

// On lit la valeur située a la ligne voulue dans le fichier désigné
nCurDegree = LireDegree(nLineNumber, sBuffer);
// On stocke la valeur minimale lue
if (nMinDegree>nCurDegree || bFirst) 
{
bFirst = 0;
nMinDegree = nCurDegree;
}
i=0;
if (bBreak)
break;
}
else if (sBuffer[0]!=32)
i++; // le caractère lu fait partie du nom de fichier. On avance le curseur pour lire le caractère suivant
}
fprintf(fp_final, " : %f\n", nMinDegree);
bFirst = 1;
}
fclose(fp);
fclose(fp_final);

// affiche le résultat
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 çà marche si on a même plusieurs espaces entre les deux champs.

-
// on ne lira pas plus 8 caractères
for (i=0;i<8;i++)
{


- Pouvez vous m'expliquez que présente 8 ? et pourquoi ne pas dépasser le 8 ?


- C'est possible de me décrire le principe de votre solution ?

- D'après vous, est ce que il y a des cas où la solution ne marche pas bien ? C'est à dire est ce que il y a des contraintes à vérifier pour que la solution s'exécute correctement ?

- Savez vous un outil ou bien un code à ajouter au programme C ? pour savoir si nous avons un problème en dehors de la programmeur et donc il est du au problème matériel comme : débordement mémoire et sa capacité insuffisante.

Merci.
Messages postés
17288
Date d'inscription
mercredi 2 janvier 2002
Statut
Modérateur
Dernière intervention
27 septembre 2021
70
8 ? c'est arbitraire... si tu veux mettre 15 ou 255 a ta guise...
j'ignore quelles sont les contranites que tu as.

là, y a pas de controle sur le résultat de strtod etc. donc il faut que les fichiers soient correctement concus.


"C'est possible de me décrire le principe de votre solution ? "

les commentaires sont là pour ça, non ?


On lit le fichier ligne par ligne, en stockant le n° de la ligne a considérer dans les fichiers cibles.
on lit ensuite chaque fichier (aaa cdd cc....)
on passe à la ligne souhaitée, on extraies le degree
dans la boucle traitant chaque fichier, on ne garde que le degree min lu.

rien de bien complexe, en somme.


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
8 ? c'est arbitraire... si tu veux mettre 15 ou 255 a ta guise...
j'ignore quelles sont les contranites que tu as.


D'accord.
Dans mon cas, le premier champ de fichier "resultat.txt" est un entier incrémental. Il est varié entre 1 et 50000 ou bien au plus.
pas de problème ?

On lit le fichier ligne par ligne, en stockant le n° de la ligne a considérer dans les fichiers cibles.
on lit ensuite chaque fichier (aaa cdd cc....)
on passe à la ligne souhaitée, on extraies le degree
dans la boucle traitant chaque fichier, on ne garde que le degree min lu.


C'est compris.

Merci.
Messages postés
17288
Date d'inscription
mercredi 2 janvier 2002
Statut
Modérateur
Dernière intervention
27 septembre 2021
70
50000 => moins de huit caractères, donc ok ^^

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 beaucoup pour votre assistance puisque sans vos aides pertinents et votre gentillesse alors je n'arrive pas à terminer la partie programmation de mon travail.


J'arrive à accéder à une base de données à partir d'un programme c en utilisant le driver ODBC.

Je voulais faire une interface graphique en VB.net qui permet de connecter à une base de données pour remplir quelques contrôles par exemple liste de plus il y a des boutons ..
Cette interface va générer un fichier texte.

Puis, j'ai un programme C qui va utiliser ce ficher pour faire autres traitements et donnes des résultats.

Ensuite, ces résultats obtenus seront afficher dans une liste qui fait partie de l'interface graphique.

J'ai trouvé un code qui me répond à mon besoin mais il est en VB6.
En réalité, J'ai installé Visual Studio 2008.
Lorsque j'ouvre ce projet VB6 alors l'assistance de conversion s'arrête et il me demande d'installer quelques composantes qui sont liées au visual basic 6.

Pourquoi ?


Donc, il faut refaire tout le projet VB6 de nouveau en VB.NET ou bien il y a autre solution ?

J'ai commencé à refaire le projet.
Voici le code de chargement de la 'Form1' est :
  Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        Dim cnx As ADODB.Connection
        Dim rst As ADODB.Recordset
        cnx = New ADODB.Connection
        rst = New ADODB.Recordset
        cnx.ConnectionString = "DRIVER={MySQL ODBC 3.51 Driver};" & "SERVER=127.0.0.1;" & "DATABASE=base_donnee;" & "UID=root;" & "PWD=;"
        cnx.Open()
        rst.Open("show tables", cnx)
        While Not (rst.EOF)
            ComboBox1.Items.Add(rst.Fields(0).Value)
            rst.MoveNext()
        End While
        rst.Close()

    End Sub


Lors de la compilation, j'ai les erreurs suivants au niveau compilation:

c:\ch\ch\Form1.Designer.vb(80) : error BC30002: Type 'ADOB.Connection' non défini.
c:\ch\ch\Form1.Designer.vb(81) : error BC30002: Type 'ADODB.Recordset' non défini.
c:\ch\ch\Form1.Designer.vb(82) : error BC30002: Type 'ADODB.Connection' non défini.
c:\ch\ch\Form1.Designer.vb(83) : error BC30002: Type 'ADODB.Recordset' non défini.



Que signifie ces erreurs et comment les résoudre ?

Comment préparer et exécuter une requete SQL en VB.net ?
par exemple dans notre cas la requête SQL est : "show tables"

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

Je voulais savoir le nombre de concepts existant dans le fichier xml.
La valeur recherchée est égale à la valeur de champ "numbercpt".
Dans notre exemple, nous allons afficher comme résultat 16.

Comment on va extraire cette valeur et l'afficher ?

Nous intéressons seulement à la partie suivante du fichier xml:
<lattice numberobj="4" numberatt="4" numbercpt="16">



Voici le fichier xml suivant "input.xml":

<galicia_document>
<lattice numberobj="4" numberatt="4" numbercpt="16">
<name>lattice(ctx_0)</name>
<object>3</object>
<object>2</object>
<object>1</object>
<object>4</object>
d
b
c
a
<concept>
 1 
<extent>
<object_ref>3</object_ref>
<object_ref>2</object_ref>
<object_ref>1</object_ref>
<object_ref>4</object_ref>
</extent>




</concept>
<concept>
 16 
<extent>
<object_ref>2</object_ref>
<object_ref>1</object_ref>
<object_ref>4</object_ref>
</extent>

d


<concept_ref>1</concept_ref>

</concept>
<concept>
 2 
<extent>
<object_ref>3</object_ref>
<object_ref>2</object_ref>
<object_ref>1</object_ref>
</extent>

a


<concept_ref>1</concept_ref>

</concept>
<concept>
 8 
<extent>
<object_ref>3</object_ref>
<object_ref>2</object_ref>
<object_ref>4</object_ref>
</extent>

c


<concept_ref>1</concept_ref>

</concept>
<concept>
 4 
<extent>
<object_ref>3</object_ref>
<object_ref>1</object_ref>
<object_ref>4</object_ref>
</extent>

b


<concept_ref>1</concept_ref>

</concept>
<concept>
 14 
<extent>
<object_ref>1</object_ref>
<object_ref>4</object_ref>
</extent>

d
b


<concept_ref>16</concept_ref>
<concept_ref>4</concept_ref>

</concept>
<concept>
 15 
<extent>
<object_ref>2</object_ref>
<object_ref>1</object_ref>
</extent>

d
a


<concept_ref>16</concept_ref>
<concept_ref>2</concept_ref>

</concept>
<concept>
 6 
<extent>
<object_ref>3</object_ref>
<object_ref>4</object_ref>
</extent>

b
c


<concept_ref>8</concept_ref>
<concept_ref>4</concept_ref>

</concept>
<concept>
 3 
<extent>
<object_ref>3</object_ref>
<object_ref>1</object_ref>
</extent>

b
a


<concept_ref>2</concept_ref>
<concept_ref>4</concept_ref>

</concept>
<concept>
 13 
<extent>
<object_ref>2</object_ref>
<object_ref>4</object_ref>
</extent>

d
c


<concept_ref>16</concept_ref>
<concept_ref>8</concept_ref>

</concept>
<concept>
 7 
<extent>
<object_ref>3</object_ref>
<object_ref>2</object_ref>
</extent>

c
a


<concept_ref>2</concept_ref>
<concept_ref>8</concept_ref>

</concept>
<concept>
 10 
<extent>
<object_ref>2</object_ref>
</extent>

d
c
a


<concept_ref>15</concept_ref>
<concept_ref>13</concept_ref>
<concept_ref>7</concept_ref>

</concept>
<concept>
 11 
<extent>
<object_ref>1</object_ref>
</extent>

d
b
a


<concept_ref>14</concept_ref>
<concept_ref>15</concept_ref>
<concept_ref>3</concept_ref>

</concept>
<concept>
 5 
<extent>
<object_ref>3</object_ref>
</extent>

b
c
a


<concept_ref>6</concept_ref>
<concept_ref>3</concept_ref>
<concept_ref>7</concept_ref>

</concept>
<concept>
 12 
<extent>
<object_ref>4</object_ref>
</extent>

d
b
c


<concept_ref>14</concept_ref>
<concept_ref>6</concept_ref>
<concept_ref>13</concept_ref>

</concept>
<concept>
 9 
<extent>
</extent>

d
b
c
a


<concept_ref>10</concept_ref>
<concept_ref>11</concept_ref>
<concept_ref>5</concept_ref>
<concept_ref>12</concept_ref>

</concept>
</lattice>
</galicia_document>


Je vais appeler votre solution comme une fonction dan mon programme pour afficher le résultat souhaité.

Je souhaite que vous m'aidez.

Merci.
Messages postés
17288
Date d'inscription
mercredi 2 janvier 2002
Statut
Modérateur
Dernière intervention
27 septembre 2021
70
heureusement que j'ai commenté mon code....

_countCpt correspond à quoi, d'après toi, dans le code source que je t'ai écrit ?


void startElement(void *user_data, const xmlChar *name, const xmlChar **attrs){
int i;

// Si on est sur un Lattice...
if (!xmlStrcmp(name, (xmlChar*)"Lattice") && attrs) {
  // On parcoure les attributs
  for (i = 0; attrs[i]; i+=2) {
    // Jusqu'à trouver l'atribut numberCpt
    if (!xmlStrcmp(attrs[i], (xmlChar*)"numberCpt")) {
        // Que l'on mémorise (strtol permet d'analyser la valeur texte, pour en faire une valeur numérique)
_countCpt = strtol((const char*)attrs[i+1],NULL,0);
...






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,

C'est à dire il suffit de faire:

printf("%d\n",_countCpt);


C'est çà ?
Messages postés
17288
Date d'inscription
mercredi 2 janvier 2002
Statut
Modérateur
Dernière intervention
27 septembre 2021
70
oui

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. Comme vous savez à part le programme 'main.c' nous avons les modules 'extraction.c' et ''extraction.h' qui contiennent les fonctions qui manipulent le fichier xml.

J'ai mis l'instruction suivante dans mon programme 'main.c':

printf("le nbre des concepts :  %d\n",_countCpt);


alors j'obtiens:
le nbre des concepts : 0


Or dans notre cas on doit obtenir :
le nbre des concepts : 16



Je voulais savoir à partir de mon programme 'main.c' en utilisant une fonction ou directement sans passer par une fonction :
le nombre des objets, le nombre des attributs et le nombre de concepts existants dans le fichier xml à manipuler .
C'est à dire on s'intéresse seulement à la partie suivante du fichier xml:

<lattice numberobj="4" numberatt="4" numbercpt="16">


Le résultat souhaité obtenu sera stocké dans un fichier et il sera affiché comme suit:


Le nombre d'objet : 4
Le nombre d'attribut : 4
Le nombre de concept : 16


Que proposez vous ?

Merci.
Messages postés
17288
Date d'inscription
mercredi 2 janvier 2002
Statut
Modérateur
Dernière intervention
27 septembre 2021
70
appelles lire_fichier avant, histoire de renseigner la variable _countCpt ...


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. Oui çà marche pour le nombre de concepts
J'ai mis:

lire_fichier("treillis.lat.xml");
printf("le nbre des concepts : %d\n",_countCpt);


Mais, comment on détermine le nombre des objets et le nombre des attributs ?
Messages postés
17288
Date d'inscription
mercredi 2 janvier 2002
Statut
Modérateur
Dernière intervention
27 septembre 2021
70
de la même manière que pour le nombre de concetps...

lit le code, suffit de s'inspirer de l'existant

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
C'est à dire il aura une modification dans la partie suivnate:

void startElement(void *user_data, 	const xmlChar *name, const xmlChar **attrs){

int i;

// Si on est sur un Lattice...

if (!xmlStrcmp(name, (xmlChar*)"Lattice") && attrs) {

// On parcoure les attributs

for (i = 0; attrs[i]; i+=2) {

// Jusqu'à trouver l'atribut numberCpt

            if (!xmlStrcmp(attrs[i], (xmlChar*)"numberCpt")) {

// Que l'on mémorise (strtol permet d'analyser la valeur texte, pour en faire une valeur numérique)

_countCpt = strtol((const char*)attrs[i+1],NULL,0);

// on alloue un tableau qui va contenir les concepts.

_concepts = (CONCEPT*)calloc(_countCpt, sizeof(CONCEPT));				

break; // inutile de considérer les attributs suivants

            }

        }

}


Mon idée:
- On va ajouter les deux variables '_countObj' et '_countAtt'qui décrivent respectivement le nombre des objets et le nombre des attributs

- on ajoute les deux instructions suivantes au partie au dessus juste après
_countCpt = strtol((const char*)attrs[i+1],NULL,0);


_countObj = strtol((const char*)attrs[i+1],NULL,0);


_countAtt = strtol((const char*)attrs[i+1],NULL,0);



Mais, çà ne marche pas.

Que proposez vous ?

Je souhaite que vous m'aidez.

Merci.
Messages postés
17288
Date d'inscription
mercredi 2 janvier 2002
Statut
Modérateur
Dernière intervention
27 septembre 2021
70
tu n'es pas loin....


regarde le test:

// Si on est sur un Lattice...
if (!xmlStrcmp(name, (xmlChar*)"Lattice") && attrs) {
   // On parcoure les attributs
   for (i = 0; attrs[i]; i+=2) {
       // Jusqu'à trouver l'atribut numberCpt
       if (!xmlStrcmp(attrs[i], (xmlChar*)"numberCpt")) {


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
Pardon, je n'arrive pas à la solution.

Pouvez vous m'aider ?

Merci.
Messages postés
17288
Date d'inscription
mercredi 2 janvier 2002
Statut
Modérateur
Dernière intervention
27 septembre 2021
70
quel est ton code actuel dans StartElement ?

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,

Pardon pour le retard car j'ai eu un problème de connexion.

Voici le code actuel de StartElement :
int _countObj = 0;  
int _countAtt = 0;  

void startElement(void *user_data, 	const xmlChar *name, const xmlChar **attrs){

int i;

// Si on est sur un Lattice...

if (!xmlStrcmp(name, (xmlChar*)"Lattice") && attrs) {

// On parcoure les attributs

for (i = 0; attrs[i]; i+=2) {

// Jusqu'à trouver l'atribut numberCpt

            if (!xmlStrcmp(attrs[i], (xmlChar*)"numberCpt")) {

// Que l'on mémorise (strtol permet d'analyser la valeur texte, pour en faire une valeur numérique)

_countCpt = strtol((const char*)attrs[i+1],NULL,0);

_countObj = strtol((const char*)attrs[i+1],NULL,0);

_countAtt = strtol((const char*)attrs[i+1],NULL,0);

// on alloue un tableau qui va contenir les concepts.

_concepts = (CONCEPT*)calloc(_countCpt, sizeof(CONCEPT));				

break; // inutile de considérer les attributs suivants

            }

        }

}

else if (!xmlStrcmp(name, (xmlChar*)"Concept") && _countCpt)

_currentCpt++;

else if (!xmlStrcmp(name, (xmlChar*)"Concept_Ref") && _countCpt)

_inUpperCovers = 1;

else if (!xmlStrcmp(name, (xmlChar*)"Attribute_Ref"))

_inIntent = 1;

else if (!xmlStrcmp(name, (xmlChar*)"Object_Ref"))

_inExtent = 1;

else if (!xmlStrcmp(name, (xmlChar*)"ID"))

_inID = 1;

}


Messages postés
17288
Date d'inscription
mercredi 2 janvier 2002
Statut
Modérateur
Dernière intervention
27 septembre 2021
70
ok, c'est bien ce que je pensais...

tu n'a pas compris le but du test if :

            if (!xmlStrcmp(attrs[i], (xmlChar*)"numberCpt")) {

// Que l'on mémorise (strtol permet d'analyser la valeur texte, pour en faire une valeur numérique)

_countCpt = strtol((const char*)attrs[i+1],NULL,0);

_countObj = strtol((const char*)attrs[i+1],NULL,0);

_countAtt = strtol((const char*)attrs[i+1],NULL,0);


c'est cool, ici tu enregistre la valeur de l'attribut numberCpt
dans trois variables distinctes... _countCpt, _countObj et _countAtt

il te faudrait pas plutot lire ces valeurs dans d'autres attributs ?


Renfield - Admin CodeS-SourceS - MVP Visual Basic