Bonjour,
Voici un nouvel article : Gestion des fichiers XML avec GTK+ de Bernard SIAUD.
Merci de donner vos avis et commentaires.
Bonjour,
Voici un nouvel article : Gestion des fichiers XML avec GTK+ de Bernard SIAUD.
Merci de donner vos avis et commentaires.
Mes remarques:
- le mélange d'anglais et de français dans le programme est assez malheureux. Je conseille à tout le monde de coder en anglais exclusivement en anglais (quitte à mettre les commentaire en français). On évite les problèmes d'accents, de position des verbes, et on favorise l'homogénéité.
- l'article évoque l'utilisation de GTK alors que seule la GLib est ici utilisés.
- l'auteur ne tire pas parti de la puissance de la GLib. À quoi sert str_isspace quand la libc fournit isspace et la GLib g_ascii_isspace ? Et mintexte quand la GLib fournit g_strstrip ?
- il y a une typo dans GmarkupDomContext où Markup devrait commencer par une majuscule.
L'article ne parle pas non plus d'une grosse limitation de GMarkupParser, pourtant évoquée dans la première ligne de l'aide officielle:
CMarkupParser n'est pas un parser XML, mais un parser d'un sous-ensemble du XML. Quid des limitations ? C'est la première chose dont il faudrait parler...Simple XML Subset Parser — parses a subset of XML
Je ne suis pas rentré dans le détail du XML (pas le temps), mais je vois des constructions comme:
C'est à éviter... Si on a deux conditions, on fait un "et" logique entre elles... On voit la limite du franglais aussi avec root->fils et root->child. Qui fait quoi ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 if (root->fils>fils) if (root->child[fils].item==(fils+texte+com)) {
Il semble aussi avoir vu des mallocs au lieu de g_malloc (malloc peut renvoyer NULL, là où g_malloc arrêtera le programme si la mémoire manque), etc.
peut être écrit:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 #define INDENT(niv) \ do \ { \ gint i; \ for (i = 1; i < (niv) - 1; i++) \ g_print ("\t"); \ } while (0)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 #define INDENT(level) \ do \ { \ gint i = level; \ while (i-- > 0) g_print ("\t"); \ } while (0)
Merci !
Il va falloir que je regarde ça ! Mais, en ce moment, le boulot me demande beaucoup !
Je viens de regarder les commentaires. C'est vrai que je ne suis pas allé aussi loin dans l'étude du programme. Comme je l'ai indiqué en début d'article, j'ai juste corrigé et commenté un programme qui était proposé ici et peu utilisable en l'état car
1) il manquait d'explications
2) il avait quelques bugs
Je vais essayer aussi rapidement que possible de profiter de ces remarques pour améliorer ces fonctions que j'utilise par ailleurs. Je vais peut-être aussi rajouter une ou deux fonctions que j'ai développées pour la lecture des ods à partir de celles déjà écrites ici.
Sinon, pour les noms en anglais, je suis tellement ignare en anglais que je préfère mettre des noms en français.
Ce code est plus rapide, mais le "while (i-- > 0)" me semble peut lisible ! J'ai plutôt tendance à dire à mes étudiants d'oublier la différence entre i++ et ++i afin de rendre lisible le code. Ici, si on met --i à la place de i--, on aura une tabulation de moins. Je ne sais si ça vaut le coup de pousser l'optimisation à ce point.
Je regarde la doc. Es-tu sûr de ce que tu dis ? Tu ne parlerais pas plutôt g_try_malloc (ou g_try_realloc)
Je continue de travailler tes remarques dès que j'ai du temps
je viens de trouver l'origine de mon travail : http://subversion.developpez.com/pro.../gmarkup-dom.c
https://developer.gnome.org/glib/2.3...et-Parser.html pour les limitations. Comme j'avoue que je suis arrivé à travailler sans problème les fichiers que je voulais modifier (des fichiers odt et ods), je ne m'étais pas rendu compte de limitations.
Ma fonction dit qu'une chaîne entière correspond à un espace alors que g_ascii_isspace signale uniquement si un caractère est un espace.
Par contre, mintexte est remplacé sans problème par g_strstrip.
Avant de passer à la modification de l'article, il faudra que je trouve l'origine de la fuite de mémoire du programme qui utilise ces fonctions. Il faudrait que je m'assure que ça ne vienne pas de là !
La fuite est là : http://www.developpez.net/forums/d13...fuite-memoire/ .
Certain. C'est dans la doc de g_try_malloc. C'est d'ailleurs l'origine de la différence de sémantique: g_try_malloc dit "essaie de m'allouer de la mémoire" (et n'échoue pas si tu n'y arrives pas), là où g_malloc dit "alloue moi de la mémoire" (et tue le programme si tu n'y arrives pas). Le comportement de malloc est (cf man 3 malloc):
Donc en cas d'échec, malloc renvoie NULL. g_malloc, lui, tue le programme, faisant en sorte de découvrir le problème dès qu'il survient, à l'allocation du buffer, plutôt que peut être beaucoup plus tard, quand tu compterais l'utiliser, et où tu aurais un crash vu que tu tenterais d'écrire à l'adresse NULL.The malloc() and calloc() functions return a pointer to the allocated memory that is suitably aligned for any kind of variable. On error, these functions return NULL. NULL may also be returned by a successful call to malloc() with a size of zero, or by a successful call to calloc() with nmemb or size equal to zero.
g_try_malloc quant à lui sert à essayer d'allouer de gros buffers, si on n'est pas sûr d'avoir la mémoire suffisante pour cela.
OK... Encore un e fois, mon anglais me fait défaut
Pas de soucis.
Pour la doc de g_try_malloc:
qu'on peut traduire par:gpointer g_try_malloc (gsize n_bytes);
Attempts to allocate n_bytes, and returns NULL on failure. Contrast with g_malloc(), which aborts the program on failure.
n_bytes : number of bytes to allocate.
Returns : the allocated memory, or NULL.
Pour la doc de malloc:gpointer g_try_malloc (gsize n_bytes);
Tente d'allouer n_bytes octets, et renvoie NULL en cas d'échec. Contraste avec g_malloc(), qui termine le programme en cas d'échec.
n_bytes : nombre d'octets à allouer.
Renvoie : la mémoire allouée, ou NULL.
Les fonctions malloc() et calloc() retournent un pointeur vers la mémoire allouée qui est allignée de manière appropriée à n'importe quel type de variable. En cas d'erreur, ces fonctions renvoient NULL. NULL peut aussi être renvoyé par un appel réussi à malloc() avec une taille de zéro, ou par un appel réussi à calloc avec nmemb ou size égal à zéro.
Ton commentaire précédent m'avait suffit pour comprendre la subtilité du problème. Mais, merci pour cette traduction !
Bonsoir
Est-ce que ceci va pour expliquer les limitations ? J'avoue que mon anglais me pose soucis pour cette traduction.
Comme le dit la documentation, cette bibliothèque est destinée à analyser un balisage simple, juste un sous ensemble du XML. Mais ce sous ensemble m’a largement suffi pour travailler les fichiers XML de LibreOffice.
Notons les limitations*:
- seul le codage utf-8 est accepté
- pas de définitions personnelles
- les instructions de traitement (PI - Processing instruction en anglais), les commentaires et les déclarations de doctype sont transmis, mais pas interprétés.
- Pas de DTD ou de validation
Le format de balisage supporte*:
- éléments
- attributs
- 5 entités standards*: & < > " '
- Les références de caractères.
- Les articles marqués comme CDATA
Un autre problème (je picore petit à petit ce travail !).
Je ne le mets plus dans la section GTK cet article alors ! Je le met dans C ?
Ou bien je le laisse dans la section GTK car glib est développé par l'équipe gnome.
Je pense que tu peux laisser dans la section GTK, mais fais référence à la GLib dans le titre, pas à GTK.
Pour voir la version actuelle de mon travail : http://troumad.org/OOo/gtk_xml.odt
Comme j'ai modifié le code en commentant, je me dois de faire des tests avant de passer à la version définitive. J'ai rajouté deux points sur la lecture de fichiers libre office.
Bonjour
Me voilà bien gêné avec ce tuto. En effet, il me pose problème pour compiler sous windows en mode release (sous code::blocks). En mode debug, ça passe, en mode release, le programme plante dès qu'il veut rentrer dans la procédure "xml_start_element".
Avec le fichier suivant, il passe bien par la procédure "xml_com" pour traire l'entête avant de planter :
J'ai bien sûr essayé de modifier le document traité, mais, le plantage arrive toujours dès le premier appel à "xml_start_element" ou un printf("xml_start_element\n"); même en première ligne n'est pas affiché.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 <?xml version="1.0" encoding="UTF-8"?> <document />
Me voici à nouveau avec le même problème sous linux... Peut-être est-il résolu, mais, c'est assez gênant !
Il me faudrait un expert en makefile ! En effet, la compilation en mode release sous code::blocks donne un exécutable qui plante alors que si je le fais avec le makefile, ça passe. Le fait que ça plante en compilant sous code::blocks me gêne un peu tout de même...
la question est : Est-ce bien une compilation mode release ?
Voici le makefile sous linux :
Et celui pour windows (exécuté sous Linux) :
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 CC=gcc CFLAGS= -Wshadow -Winit-self -Wredundant-decls -Wcast-align -Wundef -Wfloat-equal -Winline -Wunreachable-code -Wmissing-declarations -Wmissing-include-dirs -Wswitch-enum -Wswitch-default -Wmain -Wall `pkg-config gtk+-3.0 --cflags` -export-dynamic -fpermissive LDFLAGS=`pkg-config gtk+-3.0 --libs` -export-dynamic -lzip -lm EXEC=perso SRC= $(wildcard *.c) OBJ= $(SRC:.c=.o) all: $(EXEC) $(EXEC) : $(OBJ) $(CC) -o $@ $^ $(LDFLAGS) %.o: %.c $(CC) -o $@ -c $< $(CFLAGS) clean: rm *.o mrproper: clean rm $(EXEC)
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 CC=i686-w64-mingw32-gcc CFLAGS= -Wshadow -Winit-self -Wredundant-decls -Wcast-align -Wundef -Wfloat-equal -Winline -Wunreachable-code -Wmissing-declarations -Wmissing-include-dirs -Wswitch-enum -Wswitch-default -Wmain -Wall `i686-w64-mingw32-pkg-config gtk+-3.0 --cflags` -export-dynamic -mwindows LDFLAGS=`i686-w64-mingw32-pkg-config gtk+-3.0 --libs` -lzip -mwindows -Wl,--export-all-symbols EXEC=perso.exe SRC= $(wildcard *.c) OBJ= $(SRC:.c=.o) all: $(EXEC) $(EXEC) : $(OBJ) $(CC) -o $@ $^ $(LDFLAGS) %.o: %.c $(CC) -o $@ -c $< $(CFLAGS) clean: rm *.o mrproper: clean rm $(EXEC)
Bonjour
Je viens de repérer et corriger une erreur dans le code d'origine. C'est peut-être elle qui était à l'origine du bug précédent.
Il faudra que je vois si j'ai encore ce qu'il faut pour modifier l'article...
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58 GMarkupDomNode *g_markup_dom_new (const gchar *filename, GError **error) { GMarkupParser markup_parser; /* http://library.gnome.org/devel/glib/stable/glib-Simple-XML-Subset-Parser.html#GMarkupParser */ /* mettre pour toute la fonction car dans g_markup_parse_context_new on ne passe qu'un */ /* pointeur sur son contenu, pas sa valeur : il faut le conserver pendant tout le process */ GMarkupParseContext *markup_parse_context; GMarkupDomNode * pere = (GMarkupDomNode *)malloc(sizeof(GMarkupDomNode)); /* pere doit être alloué dynamiquement car il est utilisé par la fonction appelante */ GMarkupDomContext context={0,0,pere,pere}; /* ce n'est pas le cas de context qui n'est utilisé que les fonctions appelées */ pere->name=NULL; /* initialisation de la racine du fichier XML */ pere->level=0; pere->item=0; pere->content=NULL; pere->texte=0; pere->attributs=NULL; pere->nb_att=0; pere->com=NULL; pere->nb_com=0; pere->parent=NULL; pere->child=NULL; pere->fils=0; g_return_val_if_fail (filename != NULL, context.root); /* sort de la fonction si filename ne pointe pas sur une chaîne de caractères */ { /* création du contexte*: fonctions à appeler suivant la nature de l'élément traité */ /* GMarkupParser markup_parser; c'était une mauvaise idée d'avoir fait une sous partie pour */ /* gérer cet élément et en plus de l'initier juste pour cette partie. Dès qu'on referme */ /* l'accolade, son espace mémoire est disponible pour les autres fonctions et sa valeur pourra */ /* être modifiée */ markup_parser.start_element = xml_start_element; /* cas*: ouverture de balise */ markup_parser.end_element = xml_end_element; /* cas*: fermeture de balise */ markup_parser.text = xml_text; /* cas*: texte entre les balises */ markup_parser.passthrough = xml_com; /* cas*: commentaires entre les balises */ markup_parser.error = NULL; /* cas*: erreur dans le fichier XML */ markup_parse_context = g_markup_parse_context_new (&markup_parser, 0, &context, NULL); /* http://library.gnome.org/devel/glib/stable/glib-Simple-XML-Subset-Parser.html#g-markup-parse-context-new */ } /* maintenant, on sait comment parcourir le fichier */ { gchar *text = NULL; gsize length = -1; g_file_get_contents (filename, &text, &length, error); /* passe tout le fichier filename dans la chaîne de caractères text dont la longueur sera dans lenght */ if (text != NULL) /* si on a récupéré le fichier */ { g_markup_parse_context_parse (markup_parse_context, text, length, error); /* on lance le "parsage" du fichier XML */ g_free (text), text = NULL; /* on lance le parsage du fichier XML */ } g_free (markup_parse_context), markup_parse_context = NULL; } return pere; }
Partager