IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

VBA Access Discussion :

Import XML structure complexe


Sujet :

VBA Access

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    63
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2003
    Messages : 63
    Points : 52
    Points
    52
    Par défaut Import XML structure complexe
    Bonjour à tous,

    Voici mon prob, je dois importer des fichiers XML (qui ont le même structure) dans une base de donnée access, et sin possible dans une même table.

    J'ai trouvé ce bout de code sur le forum qui me permet d'importer un fichier XML "simple" dans une table access :

    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
    Public Sub ImportXML()
     
        Dim doc As MSXML2.DOMDocument
        Dim parent As MSXML2.IXMLDOMElement
        Dim fils As MSXML2.IXMLDOMNode
     
        Dim dt As DAO.Recordset
     
        Set dt = CurrentDb.OpenRecordset("tmpimport")
        Set doc = New MSXML2.DOMDocument
     
        doc.async = False
        doc.Load ("p:\document\desktop\XML\test.xml")
        ' Recherche des noeuds IDENT
        For Each parent In doc.getElementsByTagName("commande")
            dt.AddNew
            ' parcourir noeud fils du parent
            For Each fils In parent.childNodes
                ' attribut = nom du champs
                dt.Fields(fils.nodeName) = fils.Text
            Next
            dt.Update
        Next
     
        Set doc = Nothing
        dt.Close
        Set dt = Nothing
     
    End Sub
    Je dis simple car la structure du fichier est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    <commandes>
     
    		<numCommande>1297</numCommande>
    		<numCompteClient>5.85595</numCompteClient>
    		<raisonSociale>SOCIETE FINANCIERE DE TERRASSEME</raisonSociale>
    		<SIREN>398172296</SIREN>
    </commandes>

    Mais dès que la structure est plus complexe, le code ne fonctionne plus, et je n'ai aucune idée de comment le modifier.

    Par exemple pour un fichier XML ayant 5 ou 6 enfants :
    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
    <?xml version="1.0" encoding="UTF-8"?>
    <?xml-stylesheet type="text/xsl" href="20071214_commandeRetour_v1_0.xsl"?>
    <commandes>
    	<societes>
    		<societe>
    			<IdSociete erreur="">
    				<numCommande>1297</numCommande>
    				<numCompteClient>5.85595</numCompteClient>
    				<raisonSociale>SOCIETE FINANCIERE DE TERRASSEME</raisonSociale>
    				<SIREN>398172296</SIREN>
    			</IdSociete>
    			<sites>
    				<site erreur="">
    					<SIRET>39817229600020</SIRET>
    					<raisonSociale>SOCIETE FINANCIERE DE TERRASSEME</raisonSociale>
    						<siteGestFlotte erreur="">
    						<nom>RODRIGUEZ</nom>
    						<prenom>FOUZIA</prenom>
    						<mail>claude.remetter@sofiter.fr</mail>
    						<tel>0490474748</tel>
    						<mobile></mobile>
    						<fax>0490471736</fax>
    					</siteGestFlotte>
    					<infratel erreur="">
    						<PABX erreur="">
    							<marque></marque>
    							<model></model>
    						</PABX>
     
    				</site>
    			</sites>
     
    		</societe>
    	</societes>
    </commandes>
    Merci d'avance pour votre aide, j'espère avoir été assez précis.

  2. #2
    Membre régulier
    Profil pro
    Inscrit en
    Août 2002
    Messages
    83
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 83
    Points : 107
    Points
    107
    Par défaut
    Bonjour,

    Sans plus de renseignements sur la structure de votre table et sur la structure
    du fichier XML, nous partirons sur les hypotheses suivantes:

    - Chaque noeud final du fichier XML correspond à un champs de votre table
    - Les noms des champs de la table correspondent aux noms des noeuds XML
    - Chaque balise "societe" du fichier XML correspond à un nouvel enregistrement.

    Vous pouvez partir sur la solution suivante : Parcours récursif du fichier XML
    à partir des balises "societe" rencontrées - on parcours le fichier XML de façon
    récursive tant que le noeud posséde des enfants.

    Ce qui pourrait se traduire par :

    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
     
     
    Public Sub ImportXML()
     
        Dim doc As MSXML2.DOMDocument
        Dim parent As MSXML2.IXMLDOMNode
     
        Dim dt As DAO.Recordset
     
        Set dt = CurrentDb.OpenRecordset("table1")
        Set doc = New MSXML2.DOMDocument
     
        doc.async = False
        doc.Load ("c:\xml02.xml")
        ' Recherche des noeuds de tous les noeuds "societe"
        For Each parent In doc.getElementsByTagName("societe")
            dt.AddNew
            ' Noeud societe rencontre - recursivite sur ce noeud
            Call ParcourirXML(parent, dt)
            dt.Update
        Next
     
        Set doc = Nothing
        dt.Close
        Set dt = Nothing
     
    End Sub
     
    Public Sub ParcourirXML(ByRef pere As MSXML2.IXMLDOMNode, ByRef dt As Recordset)
     
        Dim fils As MSXML2.IXMLDOMNode
        If pere.hasChildNodes Then
            For Each fils In pere.childNodes
                Call ParcourirXML(fils, dt)
            Next
        Else
          ' Test si noeud est un noeud final 
            If pere.nodeType = NODE_TEXT Then
                ' on suppose que le nom du noeud correspond au nom du champs de la table
                dt.Fields(pere.parentNode.nodeName) = pere.Text
            End If
        End If
    End Sub
    Ceci est une solution possible,

    Cordialement

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    63
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2003
    Messages : 63
    Points : 52
    Points
    52
    Par défaut
    Re,

    petit soucis avec la ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Call ParcourirXML(parent, dt)
    Erreur : Incompatibilité de Type.

    Il y a peut être un soucis avec le parametre parent et pere?

  4. #4
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    63
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2003
    Messages : 63
    Points : 52
    Points
    52
    Par défaut
    en fait c'était le paramêtre Dt qui est du type DAO.Recordset

    Ton code fonctionne super!!!

    MAIS, maintenant j'ai un autre soucis, je m'explique :

    Jusqu'à maintenant je créais 1 ligne par client en remplissant tous les champs de la table.
    Mon problème est que j'ai maintenant des données multiples sur un même client : Par exemple avec le noeud <USER>

    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
    <?xml version="1.0" encoding="UTF-8"?>
    <?xml-stylesheet type="text/xsl" href="20071214_commandeRetour_v1_0.xsl"?>
    <commandes>
    	<societes>
    		<societe>
    			<IdSociete erreur="">
    				<numCommande>1297</numCommande>
    				<numCompteClient>5.85595</numCompteClient>
    				<raisonSociale>SOCIETE FINANCIERE DE TERRASSEME</raisonSociale>
    				<SIREN>398172296</SIREN>
    			</IdSociete>
    			<sites>
    				<site erreur="">
    					<SIRET>39817229600020</SIRET>
    					<raisonSociale>SOCIETE FINANCIERE DE TERRASSEME</raisonSociale>
    						<siteGestFlotte erreur="">
    						<nom>RODRIGUEZ</nom>
    						<prenom>FOUZIA</prenom>
    						<mail>claude.remetter@sofiter.fr</mail>
    						<tel>0490474748</tel>
    						<mobile></mobile>
    						<fax>0490471736</fax>
    						<USER>
    							<ID_USER>258741</ID_USER>
    							<Type>A</Type>
    							<.....>	</....>
    						</USER>
    						<USER>
    							<ID_USER>25584</ID_USER>
    							<Type>B</Type>
    							<.....>	</....>
    						</USER>
    						<USER>
    							<ID_USER>24563</ID_USER>
    							<Type>B</Type>
    							<.....>	</....>
    						</USER>
     
     
    					</siteGestFlotte>
    					<infratel erreur="">
    						<PABX erreur="">
    							<marque></marque>
    							<model></model>
    						</PABX>
     
    				</site>
    			</sites>
     
    		</societe>
    	</societes>
    </commandes>
    Comment créer une ligne différente pour chaque USER, tout en ayant les autres champs quand même remplis, juste les champs USER différents.

    Merci d'avance pour cette nouvelle question.

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Août 2002
    Messages
    83
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 83
    Points : 107
    Points
    107
    Par défaut
    Difficile de te répondre sans connaitre exactement la structure de ton
    fichier XML ainsi que celle de tes tables, ainsi que la correspondance
    entre les différents noeuds et les différents champs de ta table.

    Tu souhaites créer un enregistrement par noeud USER avec les renseignements
    des noeuds parcourus avant ce noeuds USER, ou tu souhaite créer dans une autre
    table "USER" les sous-noeuds du noeud USER ???

    Par ailleurs, la solution, que je t'avais apporté, n'est certainement pas la
    plus optimale, ni forcément la plus générique. Elle te permettait juste d'avoir
    une idée de la façon de faire pour parcourir ton fichier XML de façon récursif,
    et de créer tes enregistrements.

    Cordialement

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    63
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2003
    Messages : 63
    Points : 52
    Points
    52
    Par défaut
    Bonjour,

    Je vais mettre mon fichier XML en ligne pour donner plus de détail,
    mais en gros c'est ce que tu disais,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    créer un enregistrement par noeud USER (ou plus bas) avec les renseignements
    des noeuds parcourus avant ce noeuds
    Je peux avoir X CLIENT avec X USER avec 1 Ligne Fixe ou Mobile avec X Services.
    Donc dans l'idéal il me faudrait 1 ligne par service différent mais en reprennant les noeuds précédents, C'est à dire, par exemple le compte client, son nom, prenom.......
    Je ne sais pas si cela est faisable....au vue de mon niveau de prog très bas!!!!

    XML ci-joint.

    Merci du temps que tu me consacres.

    Il serait peut être possible de partir du bas, c'est à dire du dernier noeud et de remonter, mais je ne trouve pas comment remplacer HasChildNodes, il n'y a pas de fonction equivalentes style HasPArentNodes :-))
    Je continue à chercher, mais je pense que si j'arrive à créer une ligne en remontant les noeud c'est gagné, enfin j'espère....
    Fichiers attachés Fichiers attachés

  7. #7
    Membre régulier
    Profil pro
    Inscrit en
    Août 2002
    Messages
    83
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 83
    Points : 107
    Points
    107
    Par défaut
    Je n'ai pas toujours très bien compris la structure de ton fichier
    XML, ni la structure de ta table ainsi que la correspondance entre
    les champs de ta table et les noeuds du fichier XML.

    Tu veux créer un enregistrement par noeud SERVICE rencontré et ensuite remonter les informations jusqu'au noeuds CLIENT ???

    Dans ce cas, tu parcours les noeuds SERVICE et ensuite tu parcours de façon
    récursive les noeuds père du noeud SERVICE trouvé jusqu'à ce que tu trouve le noeud CLIENT
    Pour la correspondance entre le nom du champs et le nom du noeud, ne connaissant
    pas la structure de ta table, je ne pourrais pas t'aider surtout que la structure
    ,par exemple des noeuds MOBILE et FIXE,est identique (S'agit-il de champs différents
    dans la table ?)

    Ci-joint exemple de code

    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
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
     
    Private Sub Commande1_Click()
     
        Dim doc As MSXML2.DOMDocument
        Dim pere As MSXML2.IXMLDOMNode
        Dim fils As MSXML2.IXMLDOMNode
        Dim dt As DAO.Recordset
     
        Set dt = CurrentDb.OpenRecordset("table2")
        Set doc = New MSXML2.DOMDocument
     
        doc.async = False
        doc.Load ("c:\test01.xml")
     
        ' Parcours fichier par noeud service
        ' ATTENTION LES FICHIERS XML SONT SENSIBLES A LA CASSE 
        ' DISTINCTION ENTRE MAJUSCULE ET MINUSCULE
     
        For Each fils In doc.getElementsByTagName("SERVICE")
            dt.AddNew
            ' PARCOURIR enfants du noeud SERVICE
            Call ParcourirXML(fils, dt)
            If Not fils.parentNode Is Nothing Then
                Set pere = fils.parentNode
                ' PARCOURIR PARENT DU NOEUD SERVICE
                Call ParcourirPere(pere, fils.nodeName, dt)
            End If
            dt.Update
        Next
     
        Set doc = Nothing
        dt.Close
        Set dt = Nothing
     
    End Sub
     
     
     
     
    Public Sub ParcourirXML(ByRef pere As MSXML2.IXMLDOMNode, ByRef dt As DAO.Recordset)
     
        ' PARCOURIR ENFANT DU NOEUD SERVICE
     
        Dim fils As MSXML2.IXMLDOMNode
        If pere.hasChildNodes Then
            For Each fils In pere.childNodes
                Call ParcourirXML(fils, dt)
            Next
        Else
            If pere.nodeType = NODE_TEXT Then
                Call CreationEnregistrement(dt, pere.parentNode.nodeName, pere.Text)
            End If
        End If
    End Sub
     
     
    Private Sub ParcourirPere(ByRef encours As MSXML2.IXMLDOMNode, ByVal nonTester As String, _
        ByRef dt As DAO.Recordset)
     
        ' ON REMONTE DANS LA HIERARCHIE DES NOEUDS JUSQU'AU NOEUDS "CLIENT"
     
        ' Variable "nonTester" reprend le nom du noeud déjà parcouru de façon à ne pas 
        ' reparcourir l'arborescence de ce noeud
     
        Dim pere As MSXML2.IXMLDOMNode
        Dim fils As MSXML2.IXMLDOMNode
     
        If encours.hasChildNodes Then
            For Each fils In encours.childNodes
                If fils.nodeName <> nonTester Then
                    Call CreationEnregistrement(dt, fils.nodeName, fils.Text)
                End If
            Next
        End If
     
        If Not encours.parentNode Is Nothing Then
            If encours.nodeName <> "CLIENT" Then
                ' REMONTE DANS L'ARBORESCENCE JUSQU'AU NOEUD "CLIENT" RENCONTRE
                Set pere = encours.parentNode
                Call ParcourirPere(pere, encours.nodeName, dt)
            End If
        End If
     
    End Sub
     
    Private Sub CreationEnregistrement(ByRef dt As DAO.Recordset, ByVal nomChamps As String, _
        ByVal valeurChamps As String)
     
        ' on parcours la table RESULTAT et on teste la correspondance entre le nom du champs
        ' et le nom du noeuds
     
        Dim champs As DAO.Field
     
        For Each champs In dt.Fields
            If champs.Name = nomChamps Then
                champs.Value = valeurChamps
                Exit For
            End If
        Next
     
     
    End Sub
    Cordialement

  8. #8
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    63
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2003
    Messages : 63
    Points : 52
    Points
    52
    Par défaut
    nostradamus, je suis impressionné de la vitesse à laquelle tu me donnes du code qui fonctionne, merci déjà pour cela, et pour le temps passé sur mon problème, qui est beaucoup trop dur pour mon niveau de compétence VBA et Prog mais malheureusement je dois le finir!!!!

    Ton code fait à 90% ce que je désirais, pour te donner plus de précision, ma table contient des champs portant le nom des nouds sans distinction, pour le moment, car comme tu l'as remarqué, certain noeud sont indentiques, et comportent les mêmes noms de champs, pour MOBILE ET FIXE ça ne pose pas de prob, par contre il y a plusieur fois le noeud "ERREUR" qui ici est écrasé à chaque fois.

    Pour le moment je n'en suis pas à ce probleme là, c'est plus sur la création de ligne. En effet le noeud "SERVICE" peut ne pas être présent mais il me faut quand même les données des noeuds supérieurs.
    Je ne sais pas si je suis assez clair, par exemple simplifié :

    CLIENT USER MOBILE/FIXE SERVICE
    0001 A 0123569874 DATA
    0001 A 0123569874 VOIX
    0001 B 0154789632
    0001 C 0125447888 DATA
    0002 A 0125874141 WEB
    0002 A 0125874141 DATA
    0002 B 0000000000
    Etc......

    Et à chaque nouvelle ligne on recupère toutes les infos précédentes même si le noeud est vide ou n'existe pas.

    Merci encore

  9. #9
    Membre régulier
    Profil pro
    Inscrit en
    Août 2002
    Messages
    83
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 83
    Points : 107
    Points
    107
    Par défaut
    Si j'ai bien compris, on parcours les noeuds USER du fichier XML.
    On regarde si le noeud USER possède des petit-fils SERVICE.
    Si oui, on crée autant d'enregistrements USER qu'il y a de noeuds
    SERVICE.
    Si non,on crée un enregistrement USER.

    Ce qui pourrait se traduire par le code suivant :
    (seule la procédure commande1_click a changé)

    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
     
    Private Sub Commande1_Click()
     
        Dim doc As MSXML2.DOMDocument
        Dim pere As MSXML2.IXMLDOMNode
        Dim fils As MSXML2.IXMLDOMNode
        Dim ssfils As MSXML2.IXMLDOMNode
        Dim list As MSXML2.IXMLDOMNodeList
        Dim dt As DAO.Recordset
     
        Set dt = CurrentDb.OpenRecordset("table2")
        Set doc = New MSXML2.DOMDocument
     
        doc.async = False
        doc.Load ("c:\test01.xml")
        ' Parcours fichier par noeud USER
        For Each fils In doc.getElementsByTagName("USER")
            ' POSSEDE-T-IL DES PETITS-FILS SERVICE
            If fils.selectNodes("*/SERVICE").length <> 0 Then
                Set list = fils.selectNodes("*/SERVICE")
                For Each ssfils In list
                    dt.AddNew
                    Call ParcourirXML(ssfils, dt)
                    If Not ssfils.parentNode Is Nothing Then
                        Set pere = ssfils.parentNode
                        Call ParcourirPere(pere, ssfils.nodeName, dt)
                    End If
                    dt.Update
                Next
            Else
                dt.AddNew
                Call ParcourirXML(fils, dt)
                If Not fils.parentNode Is Nothing Then
                    Set pere = fils.parentNode
                    Call ParcourirPere(pere, fils.nodeName, dt)
                End If
                dt.Update
            End If
     
        Next
     
        Set doc = Nothing
     
    End Sub
    Cordialement

  10. #10
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    63
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2003
    Messages : 63
    Points : 52
    Points
    52
    Par défaut
    C'est tout à fait ça, merci énormément pour ton aide, mon 1er problème est résolu. Mais je vais peut être arréter de t'embéter avec ça.

    Merci encore, je regrette maintenant mes cours de programmation de BTS, je savais bien qu'un jour ça me servirait

    Je vais maintenant attaquer la deuxième partie : automatiser ton code à plus de 350 fichiers!!!!!! pas de la tarte non plus, pour charger la base.
    Tu risques de me revoir sur le forum encore un moment.

    A bientot pour de nouvelles aventures.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 7
    Dernier message: 22/06/2013, 01h42
  2. Font , Xml & structure de programme .
    Par Clad3 dans le forum XML
    Réponses: 11
    Dernier message: 30/03/2005, 23h45
  3. Importer la structure d'une table
    Par barthelv dans le forum Outils
    Réponses: 3
    Dernier message: 05/10/2004, 12h37
  4. [langage] structures complexes et affichage
    Par mat21 dans le forum Langage
    Réponses: 5
    Dernier message: 18/02/2004, 16h38
  5. Réponses: 4
    Dernier message: 17/02/2004, 09h36

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo