VBA interrogation critères multiples base SIRENE

Ah, mais c'est intéressant cette notion de "json gigogne"!!

Tu as parfaitement raison! Et c'est là la place des \

En fait dans ce "prix de l'essence" ce champs "timetable" qui contient des \, si on le considère comme "json gigogne" et si on le lit au travers d'un ScriptControl.eval, on obtient directement un json "propre" (sans slash) qu'on traite alors comme n'importe quel sous-ensemble!

Dans cet exemple de l'essence, on a donc des horaires qui devraient correspondre aux ouvertures-fermetures des stations

Ca donne un truc genre

        Set Fld = VBA.CallByName(elem, "fields", VbGet)
        T(i, 1) = Fld.city
        ' ...

        Set TmTble = Sous_Obj(Fld.timetable)
        T(i, 8) = VBA.CallByName(TmTble.Lundi, "ouvert", VbGet) & "|" & _
                  VBA.CallByName(TmTble.Lundi, "ouverture", VbGet) & "|" & _
                  VBA.CallByName(TmTble.Lundi, "fermeture", VbGet)
        ' ...

Avec une fonction toute simple :

Function Sous_Obj(S As String) As Object
Dim ScrC As Object

    Set ScrC = CreateObject("MSScriptControl.ScriptControl")
    ScrC.Language = "JScript"
    Set Sous_Obj = ScrC.Eval("(" & S & ")")
End Function

Ta notion de "json gigogne" est juste parfaite!! Bien vu Steelson !

Pierre

14prix-essence.xlsm (28.23 Ko)

Et je viens de voir ton code qui est encore plus efficace que le mien!

Bravo!!

PS : ajout version avec code amélioré

36prix-essence.xlsm (28.89 Ko)

Ben oui, on se forme mutuellement (moi l'inconditionnel des split je finis par me mettre au VBA.CallByName bien que parfois ce soit plus ardu !).

Ah, mais c'est intéressant cette notion de "json gigogne"!!

C'est aussi ce que tu écrivais ici :

3/ une valeur peut être numérique/texte/tableau/ou un autre sous-ensemble contenant lui-même des couples clé/valeurs

Bonjour Pierre,

...de cet object on peut lire directos les éléments de niveau 1 avec un VBA.CallByName

je vais voir aussi une autre voie qui serait d'utiliser cette fonction

.AddCode "Object.prototype.item=function( i ) { return this[i] } ; "

de ce fait on pourrait peut-être accéder en une seule étape à la valeur souhaitée ...

Michel

Sans utiliser VBA.CallByName ...

Public Const BASE_SIRENE = "https://data.opendatasoft.com/api/records/1.0/search/?dataset=sirene_v3%40public&q="

Sub Lire_sirene()
Dim Url As String, Nb As Integer, idx As Integer
Dim Brut As Object, Elem As Object
Dim T As Variant

    On Error Resume Next
    With Sheets("Sirene")
        .Range("A6:L1000").ClearContents

        Url = BASE_SIRENE & .Range("A4").Value
        Set Brut = Obj_Rcdst(Url)
        Nb = Brut.nhits
        ReDim T(1 To Nb, 1 To 10)
        idx = 1
        For Each Elem In Brut.records
            With Elem.champs ' en remplacement de fields dont excel met invariablement une majuscule !
                T(idx, 1) = .enseigne1etablissement
                T(idx, 2) = .adresseetablissement
                T(idx, 3) = .denominationunitelegale
                T(idx, 4) = .regionetablissement
            End With
            idx = idx + 1
        Next Elem

        .Range("B7").Resize(UBound(T, 1), UBound(T, 2)) = T

    End With
    Set Brut = Nothing
End Sub

Function Obj_Rcdst(Url As String) As Object
Dim ScrC As Object

    With CreateObject("MSXML2.XMLHTTP")
        .Open "GET", Url, False
        .send
        Set ScrC = CreateObject("MSScriptControl.ScriptControl")
        ScrC.Language = "JScript"
        Set Obj_Rcdst = ScrC.Eval("(" & Replace(.responseText, "fields", "champs") & ")")
    End With
End Function

J'ai juste parfois un soucis avec des mots qu'excel met en majuscule (et ça coince !), comme name, address, fields etc.

52sirene.xlsm (21.86 Ko)

Bonjour à tous, Salut Steelson,

Alors dans le genre, je peux proposer ceci :

    .Language = "JScript"
    .AddCode "function getKeys(jsonObj) { var keys = new Array(); for (var i in jsonObj) { keys.push(i); } return keys; } "
    .AddCode "function getProperty(jsonObj, propertyName) { return jsonObj[propertyName]; } "

Ici, pour ce json dont on ne connait pas le jeu de clé d'avance (puisque ça fluctue dans le temps par définition -> données météo actualisées), on injecte 2 fonctions javascript pour récupérer les clés d'une part et les contenus de l'autre.

Ca permet d'avoir un code de lecture simple :

    For i = 5 To UBound(Keys)
        Set Data = GetObjectProperty(Obj, Keys(i))
        T(i + 2, 1) = Keys(i)
        T(i + 2, 2) = Data.pression.niveau_de_la_mer
        T(i + 2, 3) = Data.temperature.sol
        T(i + 2, 4) = VBA.CallByName(Data.vent_moyen, "10m", VbGet)
    Next i

(rq : affichage de quelques données brutes du site ...)

MAIS ça n'exclut pas le recours obligatoire à VBA.CallByName puisqu'on ne peut pas écrire Data.vent_moyen.10m

ni tout mot clé réservé du Vba (d'où tes majuscules dans ton code)

Pierre

Bonjour Pierre,

MAIS ça n'exclut pas le recours obligatoire à VBA.CallByName puisqu'on ne peut pas écrire Data.vent_moyen.10m

ni tout mot clé réservé du Vba (d'où tes majuscules dans ton code)

Je viens de me rendre compte qu'en ajoutant

.AddCode "Object.prototype.element=function( i ) { return this[i] } ; "

on peut alors écrire ...

    On Error Resume Next ' absence d'un élément
    For i = 0 To ScriptEngine.Run("getProperty", data.records, "length") - 1
        With data.records.element(i).element("fields")
            Range("B1").Offset(0, i) = .city
            Range("B2").Offset(0, i) = .element("name")
            Range("B3").Offset(0, i) = .element("address")
            Range("B4").Offset(0, i) = .price_gazole
            Range("B5").Offset(0, i) = .price_sp95
            Range("B6").Offset(0, i) = .price_sp98
            Range("B7").Offset(0, i) = .price_e10
            With ScriptEngine.Eval("(" + CStr(.timetable) + ")")
                Range("B8").Offset(0, i) = .Lundi.ouverture & " - " & .Lundi.fermeture
                Range("B9").Offset(0, i) = .Mardi.ouverture & " - " & .Mardi.fermeture
                Range("B10").Offset(0, i) = .Mercredi.ouverture & " - " & .Mercredi.fermeture
                Range("B11").Offset(0, i) = .Jeudi.ouverture & " - " & .Jeudi.fermeture
                Range("B12").Offset(0, i) = .Vendredi.ouverture & " - " & .Vendredi.fermeture
                Range("B13").Offset(0, i) = .Samedi.ouverture & " - " & .Samedi.fermeture
                Range("B14").Offset(0, i) = .Dimanche.ouverture & " - " & .Dimanche.fermeture
            End With
        End With
    Next

ce qui semble résoudre ce problème pour les mots réservés !

et du coup mettre aussi en variable .element(_____ma_variable____)

Michel

Pierre,

je me suis fait plaisir avec ton excellente application -que j'utilise tous les jours- en appliquant le prototypage (réminiscence des mes années javascript)

Sub prev_meteo()

    Dim ScriptEngine As Object
    Set ScriptEngine = CreateObject("ScriptControl")
    ScriptEngine.Language = "JScript"
    ScriptEngine.AddCode "Object.prototype.element=function(i){return this[i]};"

    Dim data As Object, jour As Object, j%, h%, i%, t(1 To 30, 1 To 9) As Variant
    Sheets("prev").Select
    Range("A1").CurrentRegion.Offset(1, 0).ClearContents

    With CreateObject("MSXML2.XMLHTTP")
        .Open "GET", [www], False
        .send
        Set data = ScriptEngine.Eval("(" + CStr(.responsetext) + ")")
    End With

    For j = 0 To 4
        Set jour = data.element("fcst_day_" & j) ' paramètre variable
        For h = 0 To 20 Step 4
            i = j * 6 + h / 4 + 1
            t(i, 1) = i
            t(i, 2) = horodatage(jour.element("date"), h)  ' date = mot réservé
            With VBA.CallByName(jour.hourly_data, h & "H00", VbGet)
                t(i, 3) = .TMP2m
                t(i, 4) = Int(.WNDSPD10m)
                t(i, 5) = Int(.WNDGUST10m)
                t(i, 6) = .WNDDIRCARD10
                t(i, 7) = .element("CONDITION") ' Condition = mot réservé
                t(i, 8) = .PRMSL
                t(i, 9) = .APCPsfc
            End With
        Next
    Next

    ActiveSheet.Range("A2").Resize(UBound(t, 1), UBound(t, 2)) = t
    Set jour = Nothing
    Set data = Nothing

End Sub

Function horodatage(Dt As String, heure As Integer) As String
    horodatage = Mid(Dt, 4, 2) & "/" & Mid(Dt, 1, 2) & "/" & Mid(Dt, 7, 4) & " " & heure & ":00"
End Function
26meteo.xlsm (30.63 Ko)

Tout à fait intéressant! Méthode à conserver dans un coin!

Pierre

J'avais oublié celui-ci

With jour.hourly_data.element(h & "H00") ' paramètre variable

bon, je passe à autre chose maintenant !

En fait, ce topic est additif ! je n'ai pas réussi à m'en dégager ... je me suis replongé dans le javascript ...

Alors dans le genre, je peux proposer ceci :

    .Language = "JScript"
    .AddCode "function getKeys(jsonObj) { var keys = new Array(); for (var i in jsonObj) { keys.push(i); } return keys; } "
    .AddCode "function getProperty(jsonObj, propertyName) { return jsonObj[propertyName]; } "

Je pense que l'on peut proposer aussi plus simple pour le nombre d'occurrences et la liste des clés d'un objet (il faudrait que je supprime encore le dernier élément vide).

        .AddCode "function N(jsonObj){return jsonObj.length;} "
        .AddCode "function cles(jsonObj){var output = ''; for (var property in jsonObj) {output += property + '||';};return output.substr(0,output.length-2);} "

Ensuite un simple split pour avoir les clés en tableau dans excel ... exemple

    TxtCles = ScriptEngine.Run("cles", data.records.element(0).element("fields"))
    TabCles = Split(TxtCles, "||")

Bon, je me suis fait d'autres fonctions, notamment les objets de l'objet, et les attributs (couple clé/valeur) d'un objet.

Sub test()

    Dim ScriptEngine As Object
    Set ScriptEngine = CreateObject("ScriptControl")
    With ScriptEngine
        .Language = "JScript"
        .AddCode "Object.prototype.element=function( i ) { return this[i] } ; "
        .AddCode "function N(jsonObj){return jsonObj.length;} "
        .AddCode "function attributs(jsonObj){var output = ''; for (var property in jsonObj) {if ((typeof jsonObj[property] !== 'object') && (typeof jsonObj[property] !== 'function')) {output += property + '::' + jsonObj[property] + '||';};};return output.substr(0,output.length-2);} "
        .AddCode "function objets(jsonObj){var output = ''; for (var property in jsonObj) {if (typeof jsonObj[property] === 'object') {output += property + '||';};};return output.substr(0,output.length-2);} "
        .AddCode "function cles(jsonObj){var output = ''; for (var property in jsonObj) {output += property + '::' + typeof jsonObj[property] + '||';};return output.substr(0,output.length-2);} "
    End With

    Dim data As Object
    With CreateObject("MSXML2.XMLHTTP")
        .Open "GET", [www], False
        .send
        Set data = ScriptEngine.Eval("(" + CStr(.responsetext) + ")")
    End With

    TxtCles = ScriptEngine.Run("cles", data.records.element(0).element("fields"))
    TabCles = Split(TxtCles, "||")
    Sheets("keys").Select
    Cells.ClearContents
    For i = 0 To UBound(TabCles)
        Cells(i + 1, 1) = Split(TabCles(i), "::")(0)
        Cells(i + 1, 2) = Split(TabCles(i), "::")(1)
    Next

    Dim obj As Object
    Set obj = data.records.element(0).element("fields")
    Debug.Print "nb d'occurrences : "
    Debug.Print "-------------------"
    Debug.Print ScriptEngine.Run("N", data.records)
    Debug.Print
    Debug.Print "cité : "
    Debug.Print "-------"
    Debug.Print obj.city
    Debug.Print
    Debug.Print "clés de l'objet : "
    Debug.Print "------------------"
    Debug.Print ScriptEngine.Run("cles", obj) ' fields étnt un nom résrvé
    Debug.Print
    Debug.Print "attributs de l'objet : "
    Debug.Print "-----------------------"
    Debug.Print ScriptEngine.Run("attributs", obj)
    Debug.Print
    Debug.Print "objets de l'objet : "
    Debug.Print "--------------------"
    Debug.Print ScriptEngine.Run("objets", obj)
    Debug.Print

End Sub
39scriptengine.xlsm (20.34 Ko)
Rechercher des sujets similaires à "vba interrogation criteres multiples base sirene"