[EXCEL/VBA] excel2xml suite

Bonjour,
je ne suis pas expert en VBA. Ce post fait suite à celui-là notamment. J’arrive encore bien à me débrouiller avec les fonctions d’excel mais lorsqu’il faut passer aux macros en VBA 6 je suis perdu.

Du précédent post et un grand merci à gcc, je conserve ceci

Option Explicit

Sub createXmlFile()
   Dim RBase As Range, RLigne As Range, RColonne As Range
   Dim tagName As String
   
   Set RBase = Range("BaseTableau") ' nommer la première colonne du tableau "BaseTableau"

   Open "F:excel2xml.xml" For Output As 1
   Print #1, "<mon_document>"
   ' balayer les lignes
   For Each RLigne In Range(RBase.Offset(1), RBase.End(xlDown))
       'nom du node
       Print #1, "<sujet>"
       ' valeur du node
       Print #1, "  " + Mid(RLigne, 2)
       ' ecriture des childnodes
       For Each RColonne In Range(RLigne.Offset(0, 1), RLigne.End(xlToRight))
           ' Si cellule vide, on ignore
           If RColonne <> "" Then
               ' le nom de la balise est pris sur la premiere ligne
               tagName = Intersect(RBase.EntireRow, RColonne.EntireColumn)
               Print #1, "  <" + tagName + ">"
               If IsNumeric(RColonne) Then
                   Print #1, "   " + Str(RColonne)
               Else
                   Print #1, "    " + RColonne
               End If
               Print #1, "  </" + tagName + ">"
           End If
       Next
       Print #1, "</sujet>"
   Next
   Print #1, "</mon_document>"
   Close 1
End Sub

cela fonctionne très bien et je souhaite utiliser split() et vlookup() maintenant pour un traitement plus intéractif.

Prenons le cas ou mon fichier excel.xls ne contient qu’une feuille1. Dans la colonne A1 j’ai une étiquette “étiquetteA” dans la colonne B une “étiquetteB” , etc. Le code ci-dessus fonctionne bien, mais je voudrais pour la colonne D (et uniquement la colonne D), découper la chaîne de caractères (par les espaces entre caractères) du contenu de la cellule D2, D3, … Dn (“item1”, “item2”, …, “itemn”). Pour l’“item1” aller chercher dans le fichier res.xls, la feuille_res, dans la matrice A1:C6500, la colonne 2 … du genre

passer ensuite à la cellule D3, etc. et s’arrêter lorsque la cellule de la colonne A est vide ou ne contient plus d’élément. Ensuite passer à la colonne E au précédent mode :

J’ai bien testé cela

mais je n’arrive pas à l’implémenter !?

Merci,
L

Si j’ai bien compris, quand tu as traité la cellule D2, tu veux traiter tout de suite D3.
Que deviennent alors les cellules A3, B3, C3 ?

tu as tout à fait raison !!! je traite la cellule D2 et ensuite E2, F2, etc.
je me suis trompé dans mes explications … oupss

je comprends pas,


Sub createXmlFile()
   Dim RBase As Range, RLigne As Range, RColonne As Range
   Dim tagName As String, Res, Enrgt As String, Item
   
   Set RBase = Range("BaseTableau") ' nommer la première colonne du tableau "BaseTableau"

   Open "C:mon_fichier.xml" For Output As 1
   Print #1, "<?xml version=""1.0"" encoding=""ISO-8859-1""?>"
   Print #1, "<!-- mon fichier de retranscription des dialogues-->"
   Print #1, "<retranscription>"
   ' balayer les lignes
   Workbooks.Open "C:excel2xml.xls"  '**** modifier
   ThisWorkbook.Activate
   For Each RLigne In Range(RBase.Offset(1), RBase.End(xlDown))
       'nom du node
       Print #1, "<sujet>"
       ' valeur du node
       Print #1, "  " + Mid(RLigne, 2)
       ' ecriture des childnodes
       For Each RColonne In Range(RLigne.Offset(0, 1), RLigne.End(xlToRight))
           ' Si cellule vide, on ignore
           If RColonne <> "" Then
               ' le nom de la balise est pris sur la premiere ligne
               tagName = Intersect(RBase.EntireRow, RColonne.EntireColumn)
               Print #1, "  <" + tagName + ">"
               If IsNumeric(RColonne) Then
                   Print #1, "   " + Str(RColonne)
               '**** Début du traitement de la colonne D
               ElseIf RColonne.Column = 2 Then
                For Each Item In Split(RColonne)
                    Res = Application.VLookup(Item, _                  Workbooks("C:matrice_excel2xml.xls").Sheets("Feuil1").Range("A1:D6500"), 2, 0)
                    If Not Application.IsNA(Res) Then
                    Enrgt = "<attribute name=""" & Res & """" & _
                        Item & "</attribute>"
                    Print #1, Enrgt
                    End If
                Next Item
               '**** Fin du traitement de la colonne D
               Else
                   Print #1, "    " + RColonne
               End If
               Print #1, "  </" + tagName + ">"
           End If
       Next
       Print #1, "</sujet>"
   Next
   Print #1, "</retranscription>"
   Close 1
   Workbooks("C:matrice_excel2xml.xls").Close
End Sub

ne fonctionne pas !? le résultat de mon_fichier.xml est :

<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- mon fichier de retranscription des dialogues-->
<retranscription>

et il s’arrête là !

Plusieurs petites choses à modifier …

Pour Res et Item, préciser le type, sinon ça ne sert à rien de les déclarer.
Et si tu déclares tes variables, ce qui est recommandé, il vaut mieux conserver la ligne Option Explicit

Tu définis ici ton espace source. Normal ; bien noter seulement qu’il appartient au workbook actif (en principe celui qui contient la macro)

Tu ouvres un autre classeur. Pour quoi faire puisque ensuite tu n’y fais plus jamais référence ?

ThisWorkbook fait référence au classeur actif ; donc tu viens d’écrire “activer le classeur actif”

Début du traitement ; bien remarquer qu’il travaille sur le classeur d’origine (celui où a été défini le Range) et non sur le classeur actif.
Donc comme les données sont probablement dans le second, il tavaille sur une page vierge et c’est pour ca que les boucles For Each ne remontent aucune donnée

On passe au traitement de la colonne D proprement dit

Tu nous dis que tu traites la colonne D ; RColonne.Column devrait valoir 3
De plus, faire référence au numero de colonne fige ton programme (suppose que tu aies à rajouter une colonne avant celle-là, il faudrait reprendre le code) alors que tu connais le titre de la colonne (tagname)
tu peux donc écrire
ElseIf tagname = "trl"

Pour une meilleure lisibilité de ton code, il vaut mieux créer une fonction spécifique pour le traitement de la colonne D
If IsNumeric(RColonne) Then

ElseIf tagname = "trl" then
Print #1, TraitementColonneD(RColonne)
Else

End If

avec
function TraitementColonneD(ValeurCellule as String) as String
Ici tu mets ton code de split et de vlookup qui semble bon, mais au lieu de faire un print, tu concatènes dans la variable Enrgt
et tu retournes la variable en fin de fonction
TraitementColonneD = Enrgt
End function

ça c’est OK

d’accord ça aussi je comprends bien, OK

OK, mais alors là, lorsque j’enlève cette ligne

Workbooks.Open "C:excel2xml.xls"
ThisWorkbook.Activate

je conserve

Set RBase = Range("BaseTableau")

alors là, il me dit erreur, objet requis
puis fichier déjà ouvert.
Lorsque je n’utilise que

Workbooks.Open "C:excel2xml.xls"
ThisWorkbook.Activate

et supprime

Set RBase = Range("BaseTableau")

la il n’y a pas d’erreur mais s’arrête et ne remonte aucune données. Là je ne comprends plus !?

là, je ne comprends pas ce que tu me dis. En fait, les classeurs sont les mêmes : celui où je définis le Range et celui que j’active : mais là j’ai bien compris mon erreur que j’ai corrigée. Mais le problème est persistant, cf. ce que je dis plus haut

ça c’est OK aussi, je comprends. Le reste, je suis un peu perdu et je ne comprends plus. J’apprends sur le tas là. Mon split et mon vlook, je l’ai récupéré pour l’intégrer. Je ne pourrai pas dire que je comprends effectivement ce que j’ai fait. Avec des explications, il y a des choses qui rentrent et je commence à comprendre certaines choses.

Bon, j’avance un poil,
lorsque je fais pas à pas détaillé, tout se passe bien jusqu’au moment ou il arrive à la collone D, à l’étape où il me dit àla ligne

               ElseIf RColonne.Column = 3 Then
                Tablo = Split(RColonne)
                For Each Item In Split(RColonne)
                    Res = Application.VLookup(Item, _
                    Workbooks("ma_matricel.xls").Sheets("resultats").Range("A2:C6500"), 2, 0)
                    If Not Application.IsNA(Res) Then
                    Enrgt = "<attribute name="" & Res & "">" & _
                        Item & "</attribute>"
                    Print #1, Enrgt
                    End If
                Next Item

où il me dit àla ligne

                    Res = Application.VLookup(Item, _
                    Workbooks("ma_matricel.xls").Sheets("resultats").Range("A2:C6500"), 2, 0)

erreur 9 ‘l’indice n’appartient pas à la sélection’

C’est probablement qu’il ne trouve pas la valeur Item dans la colonne A2

Au moment où il te donne l’erreur, regarde quelle est la valeur de Item

OK, je suis arrivé à mes fins :


Sub createXmlFile()
   Dim RBase As Range, RLigne As Range, RColonne As Range
   Dim tagName As String, Res As String, Enrgt As String, Item, Tablo

   Set RBase = Range("BaseTableau") ' nommer la première colonne du tableau "BaseTableau"
   
   Open "c:excel2xml.xml" For Output As 1 'j'ouvre mon fichier de sortie
   Print #1, "<?xml version=""1.0"" encoding=""ISO-8859-1""?>" 'importan pour l'affichage
   Print #1, "<!-- mon fichier de retranscription des dialogues-->" 'un commentaire
   Print #1, "<retranscription>" 'mon document retranscription
   ' balayer les lignes
   Workbooks.Open "C:res_excel2xml.xls"  'j'appelle la matrive pour le vlook()
   ThisWorkbook.Activate
   For Each RLigne In Range(RBase.Offset(1), RBase.End(xlDown))
       'nom du node
       Print #1, "<sujet>"
       ' valeur du node
       Print #1, "  " + Mid(RLigne, 2)
       ' ecriture des childnodes
       For Each RColonne In Range(RLigne.Offset(0, 1), RLigne.End(xlToRight))
           ' Si cellule vide, on ignore
           If RColonne <> "" Then
               ' le nom de la balise est pris sur la premiere ligne
               tagName = Intersect(RBase.EntireRow, RColonne.EntireColumn)
               Print #1, "  <" + tagName + ">"
               If IsNumeric(RColonne) Then
                   Print #1, "   " + Str(RColonne)
               '**** Début du traitement de la colonne dialogue
               ElseIf RColonne.Column = 3 Then
                Tablo = Split(RColonne)
                For Each Item In Split(RColonne)
                    Res = Application.VLookup(Item, _
                    Workbooks("ma_matrice.xls").Sheets("res").Range("A2:C544"), 2, 0)
                    If Not Application.IsNA(Res) Then
                    Enrgt = "<attribute name=""" & Res & """>" & _
                        Item & "</attribute>"
                    Print #1, Enrgt
                    End If
                Next Item
               '**** Fin du traitement de la colonne dialogue
               Else
                   Print #1, "    " + RColonne
               End If
               Print #1, "  </" + tagName + ">"
           End If
       Next
       Print #1, "</sujet>"
   Next
   Print #1, "</retranscription>"
   Close 1
   Workbooks("ma_matrice.xls").Close     '
End Sub

l’erreur 9 ’ était à cause du path dans

Workbooks("ma_matricel.xls").Sheets("resultats").Range("A2:C6500"), 2, 0)

parce que contrairement à ce que j’ai mis sur le forum, j’avais dans mon script

Workbooks("C:ma_matricel.xls").Sheets("resultats").Range("A2:C6500"), 2, 0)

et un autre à la fermeture

   Workbooks("C:res_excel2xml.xls").Close 

qui fonctionne maintenant beaucoup mieux avec

   Workbooks("res_excel2xml.xls").Close 

Voilou,
et merci encore à toi gcc

Pour info, voici le résultat auquel je souhaitais arriver à partir de mon fichier excel :


<!-- mon fichier de retranscription des dialogues-->
	<retranscription>
	<sujet>
  Serge
<Pilote>
    Pilote
  </Pilote>
	<Dialogue>
<attribute name="INT">ah</attribute>
<attribute name="PRO:DEM">ça</attribute>
<attribute name="VER:pres">a</attribute>
<attribute name="VER:pper">bougé</attribute>
<attribute name="PRO:DEM">c'</attribute>
<attribute name="VER:pres">est</attribute>
<attribute name="PRO:DEM">ça</attribute>
<attribute name="PUN">?</attribute>
</Dialogue>
...
</retranscription>