none
Conversion Unicode vers ANSI (carctères accentués) RRS feed

  • Question

  • Bonjour,

    J'utilise dans un projet la librairie Tinyxml2 (http://leethomason.github.io/tinyxml2/) pour lire les éléments d'un fichier XML.

    Lorsque je récupère les valeurs à partir des instructions suivantes :

    tinyxml2::XMLElement* stypeDoc = attributeApproachElement->FirstChildElement("TYPEDOC"); while (stypeDoc) {
    const char* Sdoc = stypeDoc->GetText();

    stypeDoc = stypeDoc->NextSiblingElement("TYPEDOC"); m_cbo_typeDoc.InsertString(i, Sdoc); AfxMessageBox(Sdoc); i++; };

    la variable Sdoc contient bien les valeurs mais à l'affichage j'ai des caractères spéciaux à la place des accents. Par exemple, une partie de mon fichier XML est la suivante :

     <CATEGORIE NOM="ASSURANCE">
      <TYPEDOC>04-Assurance vie, Assurance décès</TYPEDOC>
     </CATEGORIE>

    Au lieu que Sdoc contienne "04-Assurance vie, Assurance décès"  le mot décès est remplacé comme suit :

    J'ai remplacé l'entête de mon fichier XML (<?xml version="1.0" encoding="UTF-8"?>) par (<?xml version="1.0" encoding="ISO-8859-1"?> mais rien à faire.

    Auriez-vous une idée comment pourrai-je faire pour avoir les accents?

    Concrètement, est-ce que c'est à moi d'effectuer manuellement cette ou est-ce que c'est la librairie tinyxml2 qui devrait prendre en charge cette opération?

    Merci d'avance pour toute aide. 

    Cordialement,

    dimanche 15 octobre 2017 12:52

Réponses

  • Oui, pas besoin de réinventer la roue.

    Le test que j'ai fait rapidement avec ton fichier, principalement par des copier-coller des codes de MS, donc rien d'original =>

    {
    	HRESULT               hr;
    	IXMLDOMElement*       pXMLElement;
    	IXMLDOMNodeList*      pXMLNodeList;
    	IXMLDOMNode*          pXMLNode;
    	CComVariant           varValue;				
    	long                  lCount = 0;
    	VARIANT_BOOL          bIsSuccessful;
    
    	hr = CoInitialize(NULL);
    	IXMLDOMDocument2* pXMLDocument;
    	hr = CoCreateInstance(CLSID_DOMDocument60, NULL, CLSCTX_INPROC_SERVER, IID_IXMLDOMDocument2, (void**)&pXMLDocument);
    	if (hr == S_OK)
    	{
    		varValue = "E:\\Sources\\MSXML\\Test.xml";
    		hr = pXMLDocument->load(varValue, &bIsSuccessful);
    		if (bIsSuccessful)
    		{
    			hr = pXMLDocument->get_documentElement(&pXMLElement);
    			if (hr == S_OK)
    			{
    				BSTR bstrRootName;
    				hr = pXMLElement->get_nodeName(&bstrRootName);
    				if (hr == S_OK)
    				{
    					WCHAR wsText[255] = L"";
    					swprintf(wsText, L"Root: %s\n", bstrRootName);
    					OutputDebugString(wsText);
    					hr = pXMLElement->get_childNodes(&pXMLNodeList);
    					if (hr == S_OK)
    					{
    						hr = pXMLNodeList->get_length(&lCount);
    						for (int i = 0; i < lCount; i++)
    						{
    							hr = pXMLNodeList->get_item(i, &pXMLNode);
    							if (hr == S_OK)
    							{
    								processNode(pXMLNode);
    								pXMLNode->Release();
    							}
    						}
    					}
    				}
    			}
    		}
    	}
    }

    Fonction récursive :

    void processNode(IXMLDOMNode *pNode)
    {
    	BSTR bstrName = NULL;
    	HRESULT hr = pNode->get_nodeName(&bstrName);
    	if (SUCCEEDED(hr))
    	{
    		WCHAR wsText[255] = L"";
    		CComVariant varNodeValue;
    		IXMLDOMNamedNodeMap* pXMLNodeMap;
    		IXMLDOMNode *pNodeB;
    		hr = pNode->get_attributes(&pXMLNodeMap);
    		if (hr == S_OK)
    		{
    			hr = pXMLNodeMap->get_item(0, &pNodeB);
    			if (hr == S_OK)
    			{
    				hr = pNodeB->get_nodeValue(&varNodeValue);
    				swprintf(wsText, L"\t%s: %s \n", bstrName, varNodeValue.bstrVal);
    				pNodeB->Release();
    			}
    			else
    			{
    				BSTR bstrText;
    				hr = pNode->get_text(&bstrText);
    				swprintf(wsText, L"\t\t%s: %s \n", bstrName, bstrText);
    				//SysFreeString(bstrText);
    			}
    			OutputDebugString(wsText);
    			pXMLNodeMap->Release();
    		}		
    		//SysFreeString(bstrName);
    	}
    	IXMLDOMNode *pChild = NULL;
    	hr = pNode->get_firstChild(&pChild);
    	if (hr == S_OK)
    	{
    		do
    		{
    			DOMNodeType type;
    			hr = pChild->get_nodeType(&type);
    			if (SUCCEEDED(hr) && (type == NODE_ELEMENT))
    				processNode(pChild);
    
    			IXMLDOMNode *pSibling = NULL;
    			hr = pChild->get_nextSibling(&pSibling);
    			if (hr != S_OK) break;
    
    			pChild->Release();
    			pChild = pSibling;
    		} while (true);
    		pChild->Release();
    	}
    }

    Principaux include/define :

    #include <MSXML6.h>
    const GUID CLSID_DOMDocument60 = { 0x88d96a05, 0xf192, 0x11d4,{ 0xa6, 0x5f, 0x00, 0x40, 0x96, 0x32, 0x51, 0xe5 } };
    #define IID_IXMLDOMDocument2 __uuidof(IXMLDOMDocument2) 
    #include <atlbase.h> // Includes CComVariant and CComBSTR.
    void processNode(IXMLDOMNode *pNode);

    Fichier de test :

    <?xml version="1.0" encoding="UTF-8"?>
    <ARCODOP>
    	<CATEGORIE NOM="ASSURANCE">
    	<TYPEDOC>01-Assurance automobile</TYPEDOC>
    	<TYPEDOC>02-Assurance habitation</TYPEDOC>
    	<TYPEDOC>03-Assurances professionnelle et scolaire</TYPEDOC>
    	<TYPEDOC>04-Assurance vie Assurance décès</TYPEDOC>
    	<TYPEDOC>05-Facture d'expertise et Certificats médicaux</TYPEDOC>
    	<TYPEDOC>06-Sinistre</TYPEDOC>
    	<TYPEDOC>07-Autres documents d'assurance</TYPEDOC>
    	</CATEGORIE>
    </ARCODOP>
    

    Résultat dans fenêtre Output :

    Root: ARCODOP
    	CATEGORIE: ASSURANCE 
    		TYPEDOC: 01-Assurance automobile 
    		TYPEDOC: 02-Assurance habitation 
    		TYPEDOC: 03-Assurances professionnelle et scolaire 
    		TYPEDOC: 04-Assurance vie Assurance décès 
    		TYPEDOC: 05-Facture d'expertise et Certificats médicaux 
    		TYPEDOC: 06-Sinistre 
    		TYPEDOC: 07-Autres documents d'assurance 

    lundi 23 octobre 2017 10:05

Toutes les réponses

  • Bonjour,
    Peut-être la solution proposée ici par Kleuter vous aidera:
    https://github.com/leethomason/tinyxml2/issues/325

    Cordialement,
    Nina


    Microsoft propose ce service gratuitement, dans le but d'aider les utilisateurs et d'élargir les connaissances générales liées aux produits et technologies Microsoft. Ce contenu est fourni "tel quel" et il n'implique aucune responsabilité de la part de Microsoft.

    lundi 16 octobre 2017 12:24
    Modérateur
  • Bonjour et merci beaucoup pour le lien vers la solution de Kleuter.
    L'auteur n'a pas en fait une solution concrète au problème car il s'est contenté de remplacer les valeurs unicodes par leur code ascii, solution qu'il qualifie lui même de "Studip". Quand on utilise un fichier xml de 2 Mo avec autant d'accents que de lignes, ce type de contournement n'est ni envisageable, ni professionnel.

    Merci encore

    mercredi 18 octobre 2017 22:57
  • J'ai remplacé l'entête de mon fichier XML (<?xml version="1.0" encoding="UTF-8"?>) par (<?xml version="1.0" encoding="ISO-8859-1"?> mais rien à faire.

    Saut erreur de ma part, Tinyxml2 est "UTF-8 only".

    Il devrait même refuser de lire des fichiers XML n'utilisant pas cet encodage.

    Si vous récupérez de mauvaise valeurs avec 'encoding="UTF-8"', c'est très vraisemblablement que le contenu du fichier n'est pas conforme à son en-tête XML.

    Le problème est donc, pour moi, dans le code générateur du XML qui ne respecte pas l'encodage du fichier XML qu'il génère.

    Après, récupérer une chaine de caractère encodé en UTF-8 dans un "const char*", c'est assez moyen si vous n'êtes pas en C++/CLI.

    Vous devriez faire une conversion entre UTF-8 et le type de chaine que vous voulez utiliser en interne :

    https://msdn.microsoft.com/magazine/mt763237


    Paul Bacelar, Ex - MVP VC++

    jeudi 19 octobre 2017 10:31
    Modérateur
  • Bonjour Paul et merci pour votre retour.

    Concernant la récupération de la valeur, effectivement j'aurai passer par la librairie standard <string> comme ceci :

    tinyxml2::XMLElement* stypeDoc = attributeApproachElement->FirstChildElement("TYPEDOC");
    while (stypeDoc) {					
      std::string utf8Text = stypeDoc->GetText();
      stypeDoc = stypeDoc->NextSiblingElement("TYPEDOC");	
      LPCTSTR sDoc = utf8Text.c_str();			
      m_cbo_typeDoc.InsertString(i, sDoc);			
      i++;
    };


    Pour le fichier XML je l'ai d'abord créé manuellement dans notepad++ puis j'ai utilisé la fonction "Convertir en UTF-8". Quand je clique ensuite sur le menu Encodage je vois bien que Encodage en UTF-8 est sélectionné, donc je me dis c'est bien encodé. 
    Malgré cela, en l'ouvrant dans mon code je me retrouve toujours avec ces mêmes caractères illisibles.

    Mon fichier est le suivant :

    <?xml version="1.0" encoding="UTF-8"?>
    <ARCODOP>
    	<CATEGORIE NOM="ASSURANCE">
    	<TYPEDOC>01-Assurance automobile</TYPEDOC>
    	<TYPEDOC>02-Assurance habitation</TYPEDOC>
    	<TYPEDOC>03-Assurances professionnelle et scolaire</TYPEDOC>
    	<TYPEDOC>04-Assurance vie Assurance décès</TYPEDOC>
    	<TYPEDOC>05-Facture d'expertise et Certificats médicaux</TYPEDOC>
    	<TYPEDOC>06-Sinistre</TYPEDOC>
    	<TYPEDOC>07-Autres documents d'assurance</TYPEDOC>
    	</CATEGORIE>
    </ARCODOP>

    L'outil XML Checker montre que c'est un XML Valide.

    D'aucun me proposent de remplacer les caractères accentués par leurs codes XML, ce qui ne me semble pas une solution car mon fichier complet est d'environ 2Mo...

    samedi 21 octobre 2017 09:42
  • J'ai fait un test (VS 2015, Windows 10) avec ton fichier et les interfaces IXMLDOMDocument2, IXMLDOMElement, ...

    et je n'ai pas ce problème d'accents.

    dimanche 22 octobre 2017 10:18
  • Bonjour Castorix31,

    Merci pour ton retour.

    Je pense que le problème est lié à la librairie Tinyxml2 qui comme le signalait @Paul Bacelar, est en UFT-8 seulement. Apparemment de ce que j'ai lu sur les forums il n'est pas ami avec les accents et plusieurs personnes ont dû mettre les codes de caractères dans leur fichier XML pour éviter le problème.
    Je n'ai pas utilisé les bibliothèques IXMLDOMDocument2, IXMLDOMDocument....pour ne pas réinventer la roue alors que l'on dispose déjà des bibliothèques toutes prêtes. Je n'en ai pas trouvé toute faite avec les objets Microsoft. Mais bon au final, je vais peut-être finir par écrire u code avec IXMLDOMDocument...pour arriver à résoudre mon problème et ne pas perdre trop de temps

    dimanche 22 octobre 2017 16:57
  • >j'aurai passer par la librairie standard <string>

    std::string n'est pas plus "UTF-8" aware que ne l'est char.

    Lisez attentivement l'article dont j'ai fourni l'URL pour voir comment gérer des chaines en UTF-8.

    Si vous avez bien vérifié la conformité du fichier XML en entré, reste le problème de la prise en charge de l'UTF-8 dans votre programme.

    >le problème est lié à la librairie Tinyxml2

    Plutôt à votre utilisation dans votre programme.

    Oui la librairie Tinyxml2 est limitée à UTF-8 mais vous l'utilisez dans son cadre d'usage.

    > IXMLDOMDocument2, IXMLDOMDocument....pour ne pas réinventer la roue

    Heu, justement, ces interfaces ont été implémentées par toute une ribambelle de composant COM, donc absolument rien à réinventer, c'est déjà implémenter.

    L'usage d'un seul, qui fait correctement son travail de dés-encodage, c'est au moins aussi simple que l'usage d'une bibliothèque Tiny-machin-bidule qui fait que la moitié du boulot.

    >Je n'en ai pas trouvé toute faite avec les objets Microsoft.

    https://msdn.microsoft.com/fr-fr/library/ms761358(v=vs.85).aspx


    Paul Bacelar, Ex - MVP VC++

    lundi 23 octobre 2017 09:15
    Modérateur
  • Oui, pas besoin de réinventer la roue.

    Le test que j'ai fait rapidement avec ton fichier, principalement par des copier-coller des codes de MS, donc rien d'original =>

    {
    	HRESULT               hr;
    	IXMLDOMElement*       pXMLElement;
    	IXMLDOMNodeList*      pXMLNodeList;
    	IXMLDOMNode*          pXMLNode;
    	CComVariant           varValue;				
    	long                  lCount = 0;
    	VARIANT_BOOL          bIsSuccessful;
    
    	hr = CoInitialize(NULL);
    	IXMLDOMDocument2* pXMLDocument;
    	hr = CoCreateInstance(CLSID_DOMDocument60, NULL, CLSCTX_INPROC_SERVER, IID_IXMLDOMDocument2, (void**)&pXMLDocument);
    	if (hr == S_OK)
    	{
    		varValue = "E:\\Sources\\MSXML\\Test.xml";
    		hr = pXMLDocument->load(varValue, &bIsSuccessful);
    		if (bIsSuccessful)
    		{
    			hr = pXMLDocument->get_documentElement(&pXMLElement);
    			if (hr == S_OK)
    			{
    				BSTR bstrRootName;
    				hr = pXMLElement->get_nodeName(&bstrRootName);
    				if (hr == S_OK)
    				{
    					WCHAR wsText[255] = L"";
    					swprintf(wsText, L"Root: %s\n", bstrRootName);
    					OutputDebugString(wsText);
    					hr = pXMLElement->get_childNodes(&pXMLNodeList);
    					if (hr == S_OK)
    					{
    						hr = pXMLNodeList->get_length(&lCount);
    						for (int i = 0; i < lCount; i++)
    						{
    							hr = pXMLNodeList->get_item(i, &pXMLNode);
    							if (hr == S_OK)
    							{
    								processNode(pXMLNode);
    								pXMLNode->Release();
    							}
    						}
    					}
    				}
    			}
    		}
    	}
    }

    Fonction récursive :

    void processNode(IXMLDOMNode *pNode)
    {
    	BSTR bstrName = NULL;
    	HRESULT hr = pNode->get_nodeName(&bstrName);
    	if (SUCCEEDED(hr))
    	{
    		WCHAR wsText[255] = L"";
    		CComVariant varNodeValue;
    		IXMLDOMNamedNodeMap* pXMLNodeMap;
    		IXMLDOMNode *pNodeB;
    		hr = pNode->get_attributes(&pXMLNodeMap);
    		if (hr == S_OK)
    		{
    			hr = pXMLNodeMap->get_item(0, &pNodeB);
    			if (hr == S_OK)
    			{
    				hr = pNodeB->get_nodeValue(&varNodeValue);
    				swprintf(wsText, L"\t%s: %s \n", bstrName, varNodeValue.bstrVal);
    				pNodeB->Release();
    			}
    			else
    			{
    				BSTR bstrText;
    				hr = pNode->get_text(&bstrText);
    				swprintf(wsText, L"\t\t%s: %s \n", bstrName, bstrText);
    				//SysFreeString(bstrText);
    			}
    			OutputDebugString(wsText);
    			pXMLNodeMap->Release();
    		}		
    		//SysFreeString(bstrName);
    	}
    	IXMLDOMNode *pChild = NULL;
    	hr = pNode->get_firstChild(&pChild);
    	if (hr == S_OK)
    	{
    		do
    		{
    			DOMNodeType type;
    			hr = pChild->get_nodeType(&type);
    			if (SUCCEEDED(hr) && (type == NODE_ELEMENT))
    				processNode(pChild);
    
    			IXMLDOMNode *pSibling = NULL;
    			hr = pChild->get_nextSibling(&pSibling);
    			if (hr != S_OK) break;
    
    			pChild->Release();
    			pChild = pSibling;
    		} while (true);
    		pChild->Release();
    	}
    }

    Principaux include/define :

    #include <MSXML6.h>
    const GUID CLSID_DOMDocument60 = { 0x88d96a05, 0xf192, 0x11d4,{ 0xa6, 0x5f, 0x00, 0x40, 0x96, 0x32, 0x51, 0xe5 } };
    #define IID_IXMLDOMDocument2 __uuidof(IXMLDOMDocument2) 
    #include <atlbase.h> // Includes CComVariant and CComBSTR.
    void processNode(IXMLDOMNode *pNode);

    Fichier de test :

    <?xml version="1.0" encoding="UTF-8"?>
    <ARCODOP>
    	<CATEGORIE NOM="ASSURANCE">
    	<TYPEDOC>01-Assurance automobile</TYPEDOC>
    	<TYPEDOC>02-Assurance habitation</TYPEDOC>
    	<TYPEDOC>03-Assurances professionnelle et scolaire</TYPEDOC>
    	<TYPEDOC>04-Assurance vie Assurance décès</TYPEDOC>
    	<TYPEDOC>05-Facture d'expertise et Certificats médicaux</TYPEDOC>
    	<TYPEDOC>06-Sinistre</TYPEDOC>
    	<TYPEDOC>07-Autres documents d'assurance</TYPEDOC>
    	</CATEGORIE>
    </ARCODOP>
    

    Résultat dans fenêtre Output :

    Root: ARCODOP
    	CATEGORIE: ASSURANCE 
    		TYPEDOC: 01-Assurance automobile 
    		TYPEDOC: 02-Assurance habitation 
    		TYPEDOC: 03-Assurances professionnelle et scolaire 
    		TYPEDOC: 04-Assurance vie Assurance décès 
    		TYPEDOC: 05-Facture d'expertise et Certificats médicaux 
    		TYPEDOC: 06-Sinistre 
    		TYPEDOC: 07-Autres documents d'assurance 

    lundi 23 octobre 2017 10:05
  • Bonjour Castorix31,

    En effet c'est le résultat que j'attendais.

    Merci pour cet exemple que je vais garder précieusement sous le coude et si l'article de Paul ne me permet pas de résoudre ce problème j'abandonnerai tinyxml2....

    Bien à toi

    lundi 23 octobre 2017 12:50
  • Bonjour Paul, le code fourni par Castorix31 est un exemple tout fait...que je vais certainement utiliser
    lundi 23 octobre 2017 12:55
  • Si le portabilité n'est pas un problème, effectivement, le code de Castorix31 pourrait être une très bonne solution.

    Paul Bacelar, Ex - MVP VC++

    lundi 23 octobre 2017 13:49
    Modérateur
  • Bonsoir Paul,

    J'opte finalement pour la solution Castorix31 mais pour continuer la discussion, j'ai lu l'article du magazine MSDN.
    L'auteur explique bien ce qu'est UTF-8 mais aussi UTF-16 mais son article s'est focalisé sur la conversion de UTF-8 vers UTF-16 à l'aide des fonctions de l'API win32. Mais au passage ce que j'ai retenu c'est que quand on utilise l'encodage UTF-8 basé sur des unités de codes de 8 bits, un simple caractère peut servir à représenter chacun de ces unités de code en C++. dans ce cas la classe sdt::string STL qui est de type char, est une bonne option pour stocker du texte Unicode encodé en UTF-8.
    C'est pour cette raison que j'ai utilisé le code suivant :

    while (stypeDoc) {					
       std::string utf8Text = stypeDoc->GetText();
       // Converti de façon securisée size_t (STL String's length to int for wind32 APIS   
       const int utf8Length = static_cast<int>(utf8Text.length()); 		
       stypeDoc = stypeDoc->NextSiblingElement("TYPEDOC");
       LPCTSTR sDoc = utf8Text.c_str();			
       m_cbo_typeDoc.InsertString(i, sDoc);			
       i++;
    };

    puis la méthode c_str() pour convertir la valeur obtenu en constante chaîne et la rendre utilisable pour la fonction InsertString de ma combobox.

    L'inconnu dans tout cela me semble être le vrai type de donnée retourné par l'instruction stypeDoc->GetText();
    Je ne sais pas si cette fonction retourne vraiment une valeur Unicode ou pas car en utilisant char * que vous m'avez déconseillé ou en utilisant std::string STL j'obtiens la même valeur et la fonction ne plante pas. Donc le problème interviendrai peut-être avant la récupération de la valeur. Donc plutôt que de revoir tout le detail de tinyxml2 je repars sur la solution Castorix31..

    encore merci 
      

    lundi 23 octobre 2017 20:30
  • Bonjour Castorix31

    L'utilisation de IXMLDocument répond parfaitement à mon besoin mais j'ai constaté un comportement un peu anormale au niveau de la récupération des valeurs des sous-type d'éléments. Dans mon exemple, les éléments <TYPEDOC>...</TYPDEDOC>

    <?xml version="1.0" encoding="UTF-8"?>
    <ARCODOP>
    	<CATEGORIE NOM="ASSURANCE">
    	<TYPEDOC>01-Assurance automobile</TYPEDOC>
    	<TYPEDOC>02-Assurance habitation</TYPEDOC>
    	<TYPEDOC>03-Assurances professionnelle et scolaire</TYPEDOC>
    	<TYPEDOC>04-Assurance vie Assurance décès</TYPEDOC>
    	<TYPEDOC>05-Facture d'expertise et Certificats médicaux</TYPEDOC>
    	<TYPEDOC>06-Sinistre</TYPEDOC>
    	<TYPEDOC>07-Autres documents d'assurance</TYPEDOC>
    	</CATEGORIE>
    </ARCODOP>

    En effet la fonction Get_Text() au lieu de me retourner les valeurs une par une retourne toutes les valeurs en une seule fois comme ceci et tout collé :

    "01-Assurance automobile02-Assurance habitation03-Assurances professionnelle et scolaire04-Assurance vieAssurance décès05-Facture d'expertise et Certificats médicaux06-Sinistre07-Autres documents d'assurance"

    Ce qui effectivement m'oblige à parser ensuite cette valeur par du code spécifique pour récupérer les 7 valeurs TYPEDOC.

    J'ai repris votre code en supprimant la fonction recursive, ce qui allonge la taille du code même c'était plus facile à deboguer pour comprendre comment toutes les valeurs étaient retournées en une seule fois.

    La fonction prend un paramètre d'entrée qui est le nom de la catégorie, ici "ASSURANCE" dans mon exemple.

    Peut-être sauriez-vous s'il ya un moyen de récupérer ces valeurs ligne par ligne, sinon je garde l'existant.

    Voici le code complet  et merci d'avance:

    void CAddDocument::ChargerTypeDocParCategorie(char* strCategorie)
    {
    	HRESULT               hr;
    	IXMLDOMElement*       pXMLElement;
    	IXMLDOMNodeList*      pXMLNodeList;
    	IXMLDOMNode*          pXMLNode;
    	CComVariant           varValue;
    	long                  lCount = 0;
    	VARIANT_BOOL          bIsSuccessful;
    	BSTR bstrName = NULL;
    	CString szCateg("");
    
    	if (strlen(strCategorie) == 0) {
    		AfxMessageBox("Catégorie manquante comme paramètre");
    		return;
    	}
    
    	hr = CoInitialize(NULL);
    	IXMLDOMDocument2* pXMLDocument;
    	hr = CoCreateInstance(CLSID_DOMDocument60, NULL, CLSCTX_INPROC_SERVER, IID_IXMLDOMDocument2, (void**)&pXMLDocument);
    	if (hr == S_OK)
    	{
    		varValue = sFileParam;
    
    		hr = pXMLDocument->load(varValue, &bIsSuccessful);
    		if (bIsSuccessful)
    		{
    			hr = pXMLDocument->get_documentElement(&pXMLElement);
    			if (hr == S_OK)
    			{
    				BSTR bstrRootName;
    				hr = pXMLElement->get_nodeName(&bstrRootName);
    				if (hr == S_OK)
    				{
    					WCHAR wsText[255] = L"";
    					swprintf(wsText, 255, L"Root: %s\n", bstrRootName);
    					//OutputDebugString(wsText);
    					hr = pXMLElement->get_childNodes(&pXMLNodeList);
    					if (hr == S_OK)
    					{
    						hr = pXMLNodeList->get_length(&lCount);
    						for (int i = 0; i < lCount; i++)
    						{
    							hr = pXMLNodeList->get_item(i, &pXMLNode);
    							if (hr == S_OK)
    							{
    								HRESULT hr = pXMLNode->get_nodeName(&bstrName);
    								if (SUCCEEDED(hr))
    								{
    									WCHAR wsText[255] = L"";
    									CComVariant varNodeValue;
    									IXMLDOMNamedNodeMap* pXMLNodeMap;
    									IXMLDOMNode *pNodeB;
    									hr = pXMLNode->get_attributes(&pXMLNodeMap); // On essaye de récupérer les attributs des categories
    									if (hr == S_OK)
    									{
    										hr = pXMLNodeMap->get_item(0, &pNodeB);
    										if (hr == S_OK)
    										{
    											//On on vérifie que la catégorie obtenue est celle passée en paramètre
    											hr = pNodeB->get_nodeValue(&varNodeValue);
    											swprintf(wsText, 255, L"\t%s: %s \n", bstrName, varNodeValue.bstrVal);
    											szCateg = varNodeValue.bstrVal;
    											if (szCateg.CompareNoCase(strCategorie) != 0)
    											{
    												pNodeB->Release();
    												continue;
    											}
    											pNodeB->Release();
    										}
    										else
    										{											
    											//On recupére les types de document pour chaque catégorie
    											BSTR bstrText;																		
    											hr = pXMLNode->get_text(&bstrText);
    											swprintf(wsText, 255, L"\t\t%s: %s \n", bstrName, bstrText);
    											CString szTypeDoc(bstrText);
    											CString sMsg("");
    											sMsg.Format("Le type de document N° %d pour la catégorie %s est %s ", i, szCateg, szTypeDoc);
    											AfxMessageBox(sMsg);
    											if (szCateg.CompareNoCase(strCategorie) == 0) {
    												m_cbo_typeDoc.AddString(szTypeDoc);												
    												szTypeDoc.Empty();
    												break; // sinon la fonction retourne 2 fois les mêmes valeurs
    											}																					
    										}
    										pXMLNodeMap->Release();
    									}									
    								}
    								//Les éléments XML de type <TYPEDOC> sont utilisés à partir de là
    								IXMLDOMNode *pChild = NULL;
    								hr = pXMLNode->get_firstChild(&pChild);
    								if (hr == S_OK)
    								{
    									do
    									{
    										DOMNodeType type;
    										hr = pChild->get_nodeType(&type);
    										if (SUCCEEDED(hr) && (type == NODE_ELEMENT))
    										{
    											HRESULT hr = pChild->get_nodeName(&bstrName);
    											if (SUCCEEDED(hr))
    											{
    												WCHAR wsText[255] = L"";
    												CComVariant varNodeValue;
    												IXMLDOMNamedNodeMap* pXMLNodeMap;
    												IXMLDOMNode *pNodeC;
    												hr = pChild->get_attributes(&pXMLNodeMap); // On essaye de récupérer les attributs des categories
    												if (hr == S_OK)
    												{
    													hr = pXMLNodeMap->get_item(0, &pNodeC);
    													if (hr == S_OK)
    													{
    														//On on vérifie que la catégorie obtenue est celle passée en paramètre
    														hr = pNodeC->get_nodeValue(&varNodeValue);
    														swprintf(wsText, 255, L"\t%s: %s \n", bstrName, varNodeValue.bstrVal);
    														szCateg = varNodeValue.bstrVal;
    														if (szCateg.CompareNoCase(strCategorie) != 0)
    														{
    															pNodeC->Release();
    															continue;
    														}
    														pNodeC->Release();
    													}
    													else
    													{
    														//On recupére les types de document pour chaque catégorie
    														BSTR bstrText;
    														hr = pXMLNode->get_text(&bstrText);
    														swprintf(wsText, 255, L"\t\t%s: %s \n", bstrName, bstrText);
    														CString szTypeDoc(bstrText);
    														if (szCateg.CompareNoCase(strCategorie) == 0) {
    															m_cbo_typeDoc.AddString(szTypeDoc);															
    															szTypeDoc.Empty();
    														}
    														break; // sinon la fonction retourne 2 fois les mêmes valeurs
    													}
    													pXMLNodeMap->Release();
    												}
    											}
    										}
    										IXMLDOMNode *pSibling = NULL;
    										hr = pChild->get_nextSibling(&pSibling);
    										if (hr != S_OK) break;
    										pChild->Release();
    										pChild = pSibling;
    									} while (true);
    
    									pChild->Release();
    								}
    								pXMLNode->Release();
    							}
    						}
    					}
    				}
    			}
    		}
    	}
    }

    jeudi 26 octobre 2017 16:56
  • C'était le but de la fonction récursive, en bouclant sur les childs

    pour appeler pNode->get_text() si pXMLNodeMap->get_item() != S_OK

    jeudi 26 octobre 2017 18:34