OVH Cloud OVH Cloud

XML en C++ : générer le xml et le parser

101 réponses
Avatar
noone
Bonjour,

je débute en C++ (j'ai fait un peu de C# avant)
L'avantage du C# était de pouvoir sérialiser facilement des objets c'est
à dire les stocker en XML.

Je ne sais pas trop comment m'y prendre en C++.

Quelle librairie utiliser (dans un projet utilisant déjà wxWidgets pour
l'interface graphique) ?

Pour les stocker je fais ceci :

// ===============================

#include <iostream> // pour cout
#include <fstream> // pour ofstream

using namespace std;

class Complexe {
public:
double x;
double y;

void Show()
{
cout << this->x << "+i*" << this->y << endl;
}
};

ostream & operator << (ostream & o,const Complexe & c)
{
return o
<< "<?xml version=\"1.0\"?>" << endl
<< "<Complexe" << " "
<< "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" << endl
<< "<Re>" << c.x << "</Re>" << endl
<< "<Im>" << c.y << "</Im>" << endl
<< "</Complexe>" << endl;
}


int main()
{
Complexe cplx;
cplx.x=1;
cplx.y=2;

cplx.Show();

ofstream ofs("cplx.xml");

ofs << cplx << endl;
cout << cplx << endl;
}

// ======================


C'est un peu lourd à gérer non ?

Donc en clair avez vous une technique pour générer du xml simplement (et
avec fiabilité) ?

Comment parser ensuite ce fichier XML ?

Merci d'avance de vos réponses.

10 réponses

Avatar
drkm
writes:

Gagnant en terme de quoi? Je parlais de la facilité à trouver
quelqu'un de compétent pour reprendre le code / réutiliser les
fichiers correspondants. Je ne pense pas que beaucoup de gens soient
compétents en théorie des langages, chose qu'il faut voir un minimum
pour gérer soit même un parser.


Ça dépend. Un format ASCII ligne simple ne demande pas de
compétences particulières. Des std::getline() et une analyse de
chaque ligne peuvent suffire. C'est du moins bien plus simple que
d'apprendre à utiliser correctement un parseur XML.

Bien que SAX serait sans doute dans un tel cas assez simple à mettre
en oeuvre, de même que la DTD ou le schéma, pour ne pas avoir à
valider soi-même le format dans les gestionnaires SAX.

--drkm

Avatar
drkm
writes:

Seulement, je ne connais pas de façon à gérer ces
identificateurs de façon générique.


Un genre de :

std::ostringstream oss ;
oss << ( void * ) & lObjet ;
oss.string() ;

ne convient pas, pour ce genre de cas ?

J'ai toujours cru, peut-être naïvement, que cela était suffisant,
éventuellement en préfixant la chaîne si l'adresse de l'objet peut
être utilisée dans différents identifiants.

--drkm

Avatar
Loïc Joly
wrote:
Loïc Joly wrote:

Un parseur XML demande lui de modifier :
- La classe
- Les fichiers de données
- Le code qui parse
- Les schéma
Ce qui en exploitation se traduit par un programme et deux fichiers.



Sauf que avec les langages supportant l'introspection, le schéma est
généré par une moulinette à partir de la classe. Il y a même de
cas où il n'y a pas besoin de générer explicitement le schéma : la
mécanisme de sérialisation le fait pour toi à la volée selon les
besoins.



Si tu utilises une génération à la volée, c'est que tu n'est pas
intéressé par respecter un format de fichier défini externement. Parce
que sinon, ton code va devoir avoir un certain nombre d'absurdités...
Par exemple, l'ordre des champs dans ta classe dans ton code va dépendre
de la spec du fichier.

Et ce qui sert dans ce cas là, c'est une bonne sérialisation aidée par
de l'introspection. Ce qui nous ramène au sujet initial. Que le format
généré soit XML ou autre n'a pas vraiment d'importance dans ce cas.

[...]


Pour moi, l'un des gros avantages de XML est qu'il est souple et qu'il
peut être utilisé de manière "crade" : je n'utilise un schéma que
si je veux effectivement valider de manière stricte un document.


Comme je le disais, le niveau de vérification apporté par les schémas
n'a rien de strict pour moi.

--
Loïc


Avatar
drkm
Loïc Joly writes:

Comme je le disais, le niveau de vérification apporté par les schémas
n'a rien de strict pour moi.


Qu'entends-tu par là ?

--drkm

Avatar
Olivier Azeau
wrote:
Gabriel Dos Reis wrote:

[...]

| ... mais parce que l'on va y trouver toute une panoplie de
| services que l'on aurait bien du mal à réécrire soi même.



*si* ces services *conviennent* à l'application donnée. Ce qui
est loin d'être acquis et c'est bien l'objet du débat (je
parle toujours de XML et non de la STL).



Mais pourquoi pas parler de la STL aussi. J'écris encore :
int i = 0 ;
et non :
std::vector< int > i( 1, 0 ) ;
Je n'utilise la STL que quand il fait quelque chose dont j'ai
besoin. Je ne l'utilise pas juste pour dire que je l'utilise, ou
parce que c'est in.

Le problème que je vois avec le XML, en fait, c'est qu'il essaie
de fournir std::map sans vouloir même admettre l'existance
possible de std::vector ni d'int.



Là, je ne comprends pas.
Un int n'existe jamais seul et quoi de plus simple de le mettre comme
attribut d'un noeud xml. Les attributs sont justement là pour ça : des
données simples.
Idem pour les vecteurs. La faculté de mettre en séquence plusieurs noeud
de même type, qu'est-ce que c'est sinon un vecteur (ou une liste) ?

C'est justement toute la puissance d'XML de pouvoir prendre en charge
simplement les choses simples et de manière plus complexe les choses
plus complexes (et de passer de l'une à l'autre sans tout casser).

Quoi de plus simple pour sérialiser:
struct X
{
int a;
};

que : <X a='13'/> ?

Et si on veut du complexe, ce n'est pas bcp plus cher. Par exemple :
struct X
{
std::vector<std::vector<int>> b;
};

<X>
<b>
<vector>
<int value='16'/>
<int value='17'/>
</vector>
<vector>
<int value='18'/>
<int value='19'/>
</vector>
</b>
</X>

Maintenant, comment faire la même chose en ASCII ? Et surtout coder en
C++ le parser associé ?


Avatar
Gabriel Dos Reis
Olivier Azeau writes:

| wrote:
| > Gabriel Dos Reis wrote:
| > [...]
| >
| >>| ... mais parce que l'on va y trouver toute une panoplie de
| >>| services que l'on aurait bien du mal à réécrire soi même.
| >
| >>*si* ces services *conviennent* à l'application donnée. Ce qui
| >>est loin d'être acquis et c'est bien l'objet du débat (je
| >>parle toujours de XML et non de la STL).
| > Mais pourquoi pas parler de la STL aussi. J'écris encore :
| > int i = 0 ;
| > et non :
| > std::vector< int > i( 1, 0 ) ;
| > Je n'utilise la STL que quand il fait quelque chose dont j'ai
| > besoin. Je ne l'utilise pas juste pour dire que je l'utilise, ou
| > parce que c'est in.
| > Le problème que je vois avec le XML, en fait, c'est qu'il essaie
| > de fournir std::map sans vouloir même admettre l'existance
| > possible de std::vector ni d'int.
| >
|
| Là, je ne comprends pas.

C'est l'analogie qui est revenu en boomerang.

-- Gaby
Avatar
Gabriel Dos Reis
Olivier Azeau writes:

[...]

| >> A quoi sert "(;)", quelle information cela apporte-t-il (machine +
| >> humain)? Si cela denote la semantique d'un complexe pour eviter
| >> d'appeler un chat un chat (i.e. prefixer par Complex),
| > Mais l'on recherche justement la manière d'appeler un chat. Selon
| > le type d'application, on peut utiliser (admettons que l'on veuille
| > fixer un membre m à j) :
| > m = #c(0 1) ;; pour reprendre la notation à CL
| > ou :
| > Member m ::= Complex 0 1
| > ou :
| > <member name="m">
| > <complex real="0" imag="1"/>
| > </member>
| >
|
| Mais le principal avantage du XML c'est que si tu trouves que la 1ère
| forme est plus lisible (question de goût), tu écris qqe chose comme ça
| :
|
| <xsl:template match="//member">
| <xsl:value-of select="@name"/> = <xsl:apply-templates/>
| </xsl:template>
| <xsl:template match="//complex">
| #c(<xsl:value-of select="@real"/> <xsl:value-of select="@imag"/>)
| </xsl:template>

C'était lisible, donc on met plus de bruit, c'est ça ?

| Et tes données ne s'afficheront pas en XML mais avec ta notation préférée.

je crois que ton newsreader te joue des tours sur le débat en cours.
La question n'est pas de faire avaler un format arbitraire à XML.

-- Gaby
Avatar
Olivier Azeau
Gabriel Dos Reis wrote:
Olivier Azeau writes:

[...]

| >> A quoi sert "(;)", quelle information cela apporte-t-il (machine +
| >> humain)? Si cela denote la semantique d'un complexe pour eviter
| >> d'appeler un chat un chat (i.e. prefixer par Complex),
| > Mais l'on recherche justement la manière d'appeler un chat. Selon
| > le type d'application, on peut utiliser (admettons que l'on veuille
| > fixer un membre m à j) :
| > m = #c(0 1) ;; pour reprendre la notation à CL
| > ou :
| > Member m ::= Complex 0 1
| > ou :
| > <member name="m">
| > <complex real="0" imag="1"/>
| > </member>
| >
|
| Mais le principal avantage du XML c'est que si tu trouves que la 1ère
| forme est plus lisible (question de goût), tu écris qqe chose comme ça
| :
|
| <xsl:template match="//member">
| <xsl:value-of select="@name"/> = <xsl:apply-templates/>
| </xsl:template>
| <xsl:template match="//complex">
| #c(<xsl:value-of select="@real"/> <xsl:value-of select="@imag"/>)
| </xsl:template>

C'était lisible, donc on met plus de bruit, c'est ça ?

| Et tes données ne s'afficheront pas en XML mais avec ta notation préférée.

je crois que ton newsreader te joue des tours sur le débat en cours.
La question n'est pas de faire avaler un format arbitraire à XML.



Il n'est pas question de faire avaler quoi que ce soit.
Qui a parlé de faire avaler un format arbitraire à XML ? pas moi en tt cas.

Je dis juste que si on critique la lisibilité de XML, il me semble
honnête de préciser que s'il existe un format facile à rendre lisible en
ASCII avec un effort minimum, c'est bien le XML.
La réciproque est généralement fausse : transformer de l'ASCII en XML,
c'est galère.

Avatar
drkm
Olivier Azeau writes:

Mais le principal avantage du XML c'est que si tu trouves que la 1ère
forme est plus lisible (question de goût), tu écris qqe chose comme ça :

<xsl:template match="//member">
<xsl:value-of select="@name"/> = <xsl:apply-templates/>
</xsl:template>
<xsl:template match="//complex">
#c(<xsl:value-of select="@real"/> <xsl:value-of select="@imag"/>)
</xsl:template>

Et tes données ne s'afficheront pas en XML mais avec ta notation préférée.
Sur un exemple aussi simple, on va me rétorquer que avec une ligne de
AWK je peux tout aussi bien faire l'inverse mais dès que l'on commence à
imbriquer des données, le XML gagne facilement.


Bof. XSLT est puissant, mais n'est pas si simple. Il suffit de
voir les articles à ce sujet sur f.c.t.xml. D'ailleurs, ton exemple
ne fonctionne pas. Un meilleur serait :

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="text" encoding="US-ASCII"/>
<xsl:strip-space elements="member complex"/>
<xsl:template match="member">
<xsl:value-of select="@name"/>
<xsl:text> = </xsl:text>
<xsl:apply-templates/>
<xsl:text>&#10;</xsl:text>
</xsl:template>
<xsl:template match="complex">
<xsl:text>#c(</xsl:text>
<xsl:value-of select="@real"/>
<xsl:text> </xsl:text>
<xsl:value-of select="@imag"/>
<xsl:text>)</xsl:text>
</xsl:template>
</xsl:stylesheet>

La question de la simplicité de la transformation est donc réglée.

--drkm

Avatar
Loïc Joly
Olivier Azeau wrote:

Quoi de plus simple pour sérialiser:
struct X
{
int a;
};

que : <X a='13'/> ?


X {a}


Et si on veut du complexe, ce n'est pas bcp plus cher. Par exemple :
struct X
{
std::vector<std::vector<int>> b;
};

<X>
<b>
<vector>
<int value='16'/>
<int value='17'/>
</vector>
<vector>
<int value='18'/>
<int value='19'/>
</vector>
</b>
</X>


Par exemple :
X{ {16, 18},
{18, 19}}



Et comment tu fais pour :
struct Y{};
struct X
{
Y* y;
};

Y y;
X x1, x2;
x1.y = x2.y = &y;

Et pour
struct B{};
struct D1:B{};
struct D2:B{};

struct X{vector<B*> data;};


Maintenant, comment faire la même chose en ASCII ? Et surtout coder en
C++ le parser associé ?


Par exemple avec boost::serialisation, ou toute autre bibliothèque de
sérialisation bien faite, çe se fait en une ligne par classe.

Les exemples ci dessus se codent ainsi (lecture et écriture d'un coup) :
Cas 1 :
Ajouter dans X (on peut aussi mettre dehors...) :
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & a;
}

Cas 2 :
Ajouter dans X :
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & b;
}

Cas 3:
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & y; // on suppose la sérialisation de y faite
}

Cas 4:
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & data; // on suppose la sérialisation de B, D1 et D2 faite
}


Et pour info, parmi les formats gérés, XML (enrichi par une sémantique
plus riche pour gérer les pointeurs) existe. Tout ça pour dire que ce
qui compte pour la facilité à coder, ce n'est pas le format de sortie,
mais uniquement la qualité de la bibliothèque de sérialisation.

--
Loïc