Bonjour à tous,

J'utilise Xeumeuleu pour manipuler le XML (lib basée sur Xercès C++ ). Je n'ai jamais eu de problème avec (je trouve quand même le XML très lourd à gérer, je ne sais pas si je referai ce choix dans le futur). A cause des difficultés rencontrées avec ce XML, j'ai introduit une petite généralisation via une classe de base pour pouvoir plus tard manipuler autre chose si besoin (CSV, etc. ). Et là c'est le drame, je n'arrive plus à gérer correctement les listes à l'intérieur d'un même noeud.
J'avoue être démuni, je cherche depuis une semaine le problème sans aucuns résultats, donc j'espère que vous aurez des meilleures idées que moi !

Voici mon main : j'écris dans un fichier XML une structure simple (deux points ici), et j'essaye ensuite de les loader à nouveau. La première solution ne marche pas, je "rentre" pas correctement dans les noeuds, alors que la deuxième marche très bien.
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
int main()
{
	{ // Write a XML file for example, works nicely
		CIoPoint point1 (1,2);
		CIoPoint point2 (3.2,4.6);
 
		xml::xofstream file_out("test.xml");
		COXMLHandler h_out (file_out);
		h_out.Start("Document");
		point1.Save(h_out);
		point2.Save(h_out);
		h_out.End();
	}
 
	// Try to read the same XML file
	xml::xifstream file_in("test.xml");
 
 
	#ifdef MY_HANDLER 
	// Doesnt'work
	CIXMLHandler h_in(file_in);
	h_in.Start("Document");
	CIXMLHandler::node_vector_ptr vect = h_in.GetNodes();
	#else
	// Works
	CXmlListLoader2<> h_in(file_in);
	file_in >> xml::start("Document");
	h_in.Load();
	CXmlListLoader2<>::vector_ptr vect = h_in.GetCollection();
	#endif
 
	return 0;
}
Voici les deux classes pour lire le XML. Elles utilisent une factory qui marche très bien. Les deux classes sont quasi identiques : une manipule mon abstraction CIXMLHandler, l'autre directement le xml:istream (le flux de Xeumeuleu).
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
 
template <class T = IIoObject>
class CXmlListLoader
{
public:
	typedef std::vector<boost::shared_ptr<T> > vector_ptr;
 
	CXmlListLoader(CIXMLHandler& handler) : m_handler(handler)  {}
 
	void Load()
	{
		xml::xistream& xis = m_handler.GetXMLStream();
		xis >> xml::list(*this, &CXmlListLoader<T>::Load );
	}
 
	const vector_ptr& GetCollection() {return m_collection;}
 
private:
 
	void Load(const std::string& , xml::xistream& xis)
	{
		try 
		{
			const std::string name = xml::attribute<std::string>(xis, "name" ); // Exception if attribute does not have a name
			boost::shared_ptr<IIoObject> node = CObjectFactory<IIoObject>::Instance().Create(name);
			node->Load(m_handler);
			m_collection.push_back(boost::static_pointer_cast<T>(node) );		
		}
		catch (const std::exception& e)
		{
			std::cout << e.what() << std::endl;
		}
	}
 
	CIXMLHandler&	m_handler;
	vector_ptr		m_collection;
};
 
template <class T = IIoObject>
class CXmlListLoader2
{
public:
	typedef std::vector<boost::shared_ptr<T> > vector_ptr;
 
	CXmlListLoader2(xml::xistream& stream) : m_stream(stream)  {}
 
	void Load()
	{
		m_stream >> xml::list(*this, &CXmlListLoader2<T>::Load );
	}
 
	const vector_ptr& GetCollection() {return m_collection;}
 
private:
 
	void Load(const std::string& , xml::xistream& xis)
	{
		try 
		{
			const std::string name = xml::attribute<std::string>(xis, "name" ); // Exception if attribute does not have a name
			boost::shared_ptr<IIoObject> node = CObjectFactory<IIoObject>::Instance().Create(name);
			node->Load(xis);
			m_collection.push_back(boost::static_pointer_cast<T>(node) );		
		}
		catch (const std::exception& e)
		{
			std::cout << e.what() << std::endl;
		}
	}
 
	xml::xistream&	m_stream;
	vector_ptr		m_collection;
};
Enfin, voici mon abstraction:
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
 
class IIHandler
{
public:
	typedef std::vector<boost::shared_ptr<IIoObject> > node_vector_ptr;
 
	IIHandler() {}
	virtual ~IIHandler() {}
 
	// Read a Node with name
	virtual void Start(const std::string& str) = 0;
 
	// Get Out of a node
	virtual void End() = 0;
 
	// Extract nodes
	virtual node_vector_ptr GetNodes() = 0;
 
	// Read Attribute
	virtual void	Attribute(const std::string& tag, std::string& value) = 0;
	virtual void	Attribute(const std::string& tag, bool& value) = 0;
	virtual void	Attribute(const std::string& tag, int& value) = 0;
	virtual void	Attribute(const std::string& tag, long& value) = 0;
	virtual void	Attribute(const std::string& tag, float& value) = 0;
	virtual void	Attribute(const std::string& tag, double& value) = 0;
	virtual void	Attribute(const std::string& tag, unsigned int& value) = 0;
	virtual void	Attribute(const std::string& tag, unsigned long& value) = 0;
 
	// Read content inside Node
	virtual void	Content(const std::string& tag, std::string& value) = 0;
	virtual void	Content(const std::string& tag, bool& value) = 0;
	virtual void	Content(const std::string& tag, int& value) = 0;
	virtual void	Content(const std::string& tag, long& value) = 0;
	virtual void	Content(const std::string& tag, float& value) = 0;
	virtual void	Content(const std::string& tag, double& value) = 0;
	virtual void	Content(const std::string& tag, unsigned int& value) = 0;
	virtual void	Content(const std::string& tag, unsigned long& value) = 0;
};
et sa classe fille pour gérer le XML, qui implémente simplement les fonctions membres virtuelles, en stockant un flux xml par référence :
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
 
class CIXMLHandler : public IIHandler
{
public:
	CIXMLHandler(xml::xistream& stream);
	virtual ~CIXMLHandler() {}
 
	// Go into Node with name
	virtual void Start(const std::string& str);
 
	// Get Out of a node
	virtual void End();
 
	// Extract nodes
	virtual node_vector_ptr GetNodes();
 
	// Read Attribute to a Node
	virtual void	Attribute(const std::string& tag, std::string& value);
	virtual void	Attribute(const std::string& tag, bool& value);
	virtual void	Attribute(const std::string& tag, int& value);
	virtual void	Attribute(const std::string& tag, long& value);
	virtual void	Attribute(const std::string& tag, float& value);
	virtual void	Attribute(const std::string& tag, double& value);
	virtual void	Attribute(const std::string& tag, unsigned int& value);
	virtual void	Attribute(const std::string& tag, unsigned long& value);
 
	// Read content inside Node
	virtual void	Content(const std::string& tag, std::string& value);
	virtual void	Content(const std::string& tag, bool& value);
	virtual void	Content(const std::string& tag, int& value);
	virtual void	Content(const std::string& tag, long& value);
	virtual void	Content(const std::string& tag, float& value);
	virtual void	Content(const std::string& tag, double& value);
	virtual void	Content(const std::string& tag, unsigned int& value);
	virtual void	Content(const std::string& tag, unsigned long& value);
 
	xml::xistream&	GetXMLStream() {return m_stream;}
 
private:
	// Manipulate input XML File
	xml::xistream& m_stream;
};
Pour info, ma classe CIoPoint est tout ce qu'il y a de plus simple, je ne montre ici que les deux fonctions Load :
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
 
void CIoPoint::Load(IIHandler& h)
{
	double x = 0, y = 0;
	h.Attribute("x", x);
	h.Attribute("y", y);
	m_point = CPoint<double>(x, y);
}
 
void CIoPoint::Load(xml::xistream& str)
{
	double x = 0, y = 0;
	str >> xml::attribute("x", x);
	str >> xml::attribute("y", y);
	m_point = CPoint<double>(x, y);
}
Au final, mon encapsulation ne marche pas. Mais je ne sais vraiment pas où. Je ne fais que transférer les appels au flux XML comme via un proxy, mais ça ne semble pas marcher. Je voulais juste éviter les appels direct à la bibliothèque Xeumeuleu en passant par une abstraction et tout encapsuler, mais il semble que quelque chose manque. J'ai pourtant tout bien passé par référence...

Je peux fournir l'exemple ci dessus en projet Visual Studio, mais il nécessite boost.TR1 , Xeumeuleu et Xercès pour fonctionner, alors je pense pas que ce soit très intéressant.

Merci pour votre aide !