Linq extraction fichier XML

Résolu
cs_JMO Messages postés 1854 Date d'inscription jeudi 23 mai 2002 Statut Membre Dernière intervention 24 juin 2018 - Modifié par Whismeril le 16/06/2015 à 22:08
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 - 20 juin 2015 à 11:06
Bonjour le Forum,

Je dispose d'un fichier xml ayant la structure suivante:

<?xml version="1.0" encoding="UTF-8"?>

<Domain name="DEV" stamp="VTEXPORT 5.6.4a FR LINUX_X64 2014/06/15">
  <Properties>
  </Properties>
  <Calendars>
    <Calendar name="TLJ" year="2015" publicHolidays="1"/>
  </Calendars>
  <Contexts/>

  <Environments>
    <Environment name="exploitation" scriptsDir="">
      <UsedCalendars names="TLJ/2020 TLJ/2021"/>
      <UsedUsers names="titi toto root"/>

      <Applications>
        <Application name="BASCULE_test_EXPLOIT" retained="0">
          <Planning planning="1" formula="0"/>

          <Jobs>

   <Job name="P9999H0102" retained="0" family="UNIX" comment="">
              <Script><![CDATA[#/opt/vtom/envoi.sh]]></Script>
              <Parameters>
                <Parameter><![CDATA[TEST]]></Parameter>
              </Parameters>
              <Node objectType="job" x="430" y="140">
              </Node>
            </Job>
    
            <Job name="PBASCULEDATE" retained="0" family="TR1|UNIX" comment="Bascule">
              <Script><![CDATA[#/opt/vtom/test_bascule_exploitation.sh]]></Script>
              <Node objectType="job" x="114" y="84">
                <Properties>
                  <Property key="content" value=""/>
                  <Property key="icon" value="trafficlight_on"/>
                </Properties>
              </Node>
            </Job>

          </Jobs>

          <Graph name="BASCULE_EXPLOIT"/>
          <Node objectType="app" x="360" y="600"/>
        </Application>


        <Application name="A-P9999H01" retained="0" comment="">
          <Planning planning="0" formula="1">
            <Formula><![CDATA[test {aujourd'hui = mercredi}]]></Formula>
          </Planning>

          <Jobs>
            <Job name="P9999H0101" retained="0" family="UNIX">
              <Script><![CDATA[#/opt/vtom/plan_production.sh]]></Script>
              <Node objectType="job" x="430" y="30">
              </Node>
            </Job>

          </Jobs>
          <Graph name="A-P9999H01">
            <Node nodeSId="GNO" y="140">
            </Node>
          </Graph>

        </Application>
      </Applications>
    </Environment>
  </Environments>
</Domain>


Je souhaite extraire les données de l'arborescence

---> Environnement
------> Application
------------> Job

Le script suivant
Private FileXML As XElement = XElement.Load("C:\Users\JMO_test_extract_XML.xml")

        Dim list = _
            From items In FileXML.Elements("Environments").Elements("Environment") _
            Select items

        For Each xEle As XElement In list
            Dim envName As String = CStr(xEle.Attribute("name").Value)
            Dim appName As String = CStr(xEle.Element("Applications").Element("Application").Attribute("name").Value)
            Dim jobName As String = CStr(xEle.Element("Applications").Element("Application").Element("Jobs").Element("Job").Attribute("name").Value)

            TextBox2.Text = TextBox2.Text + _
                            "ENV (name)" + _
                            Convert.ToChar(Keys.Tab) + envName + Environment.NewLine
            TextBox2.Text = TextBox2.Text + Convert.ToChar(Keys.Tab) + _
                            "APP (name)" + _
                            Convert.ToChar(Keys.Tab) + appName + Environment.NewLine
            TextBox2.Text = TextBox2.Text + Convert.ToChar(Keys.Tab) + Convert.ToChar(Keys.Tab) + _
                            "JOB (name)" + Convert.ToChar(Keys.Tab) + jobName + Environment.NewLine
            TextBox2.Text = TextBox2.Text + Environment.NewLine
        Next xEle

me retourne seulement
ENV (name) exploitation
APP (name) BASCULE_test_EXPLOIT
JOB (name) P9999H0102



Je souhaiterai qu'il me retourne

ENV (name) exploitation
APP (name) BASCULE_test_EXPLOIT
JOB (name) P9999H0102
JOB (name) PBASCULEDATE
APP (name) P9999H01
JOB (name) P9999H0102


xEle.ToString me renvoie correctement tous les éléments de chaque environnement.

Quelle boucle dois-je faire pour extraire les données selon l'arborescence ?

ENV1
APP1
JOB1
JOB2

APP2
JOB4

ENV2
APP3
JOB5
JOB6

Désolé pour cette présentation, les tabulations et espaces ne sont pas pris en compte.

Merci de vos suggestions et conseils.

jean-marc

EDIT: Ajout de la coloration syntaxique.

16 réponses

Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 656
17 juin 2015 à 00:09
Bonsoir,

d'abord, il te faut décrire dans une classe chaque "étage" de ton arborescence, j'en ai fait deux pour l'exemple

Imports System.Collections.Generic


Public Class Job
    '         La classe Job doir contenir ces informations (pour l'exemple je ne les faits pas toutes, mais comme tu en parameters {entre autres} qui est optionnel, je te montre
    '        <Job name="P9999H0101" retained="0" family="UNIX">
    '              <Script><![CDATA[#/opt/vtom/plan_production.sh]]></Script>
    '              <Node objectType="job" x="430" y="30">
    '              </Node>
    '        
    '         <Job name="P9999H0102" retained="0" family="UNIX" comment="">
    '              <Script><![CDATA[#/opt/vtom/envoi.sh]]></Script>
    '              <Parameters>
    '                <Parameter><![CDATA[TEST]]></Parameter>
    '              </Parameters>
    '              <Node objectType="job" x="430" y="140">
    '              </Node>
    '
    '        
    Public Property Name() As String

    Public Property Retained() As Integer

    Public Property Family() As String

    Public Property Script() As String

    Public Property Parameters() As List(Of String)
End Class

Public Class ApplicationJMO
    Public Property Name() As String

    Public Property Jobs() As List(Of Job)

    '        
    '         je te laisse faire les autres
    '         
End Class


Ensuite il faut faire une requête qui lise le fichier
Attention VB n'accepte pas les commentaires dans la requête, il te faudra les supprimer, mais là c'est pour aider à la lecture

    Private Sub xmlJMO()
        Dim xDoc As XDocument = XDocument.Load("testJMO.xml")'Chargement du fichier

        Dim maListe As List(Of ApplicationJMO) = (
            From el In xDoc.Descendants("Application")'directement le noeud qui représente l'enregistrement
            Select New ApplicationJMO With {'on crée une instance d'ApplicationJMO
                .Name = el.Attribute("name").Value,
                .Jobs = (
                    From j In el.Descendants("Job")'idem, direct le noeud Job et pas Jobs
                    Select New Job With'On crée une instance de Job
                           {
                               .Name = j.Attribute("name").Value,'les premières données sont systématiquement là
                               .Retained = Convert.ToInt32(j.Attribute("retained").Value),
                               .Family = j.Attribute("family").Value,
                               .Script = j.Element("Script").ToString(),'là je t'ai mis ToSting() au lieu de Value, car Value vire "![CDATA[" et "]]", cependant avec ToString, tu as la balise en plus, à toi de voir
                               .Parameters = If(j.Elements("Parameters").Count() = 0, Nothing, (
                                From p In j.Descendants("Parameter")
                                Select p.Value).ToList())'pour les paramètres, il faut tester s'il y en a ou pas
                           }).ToList()
                    }).ToList()


    End Sub

0
cs_JMO Messages postés 1854 Date d'inscription jeudi 23 mai 2002 Statut Membre Dernière intervention 24 juin 2018 27
17 juin 2015 à 09:40
Bonjour Whismeril,

D'abord, merci de ton temps consacré à m'expliquer la route sinueuse à emprunter.

J'ai donc déclaré dans une classe les variables (pas toutes pour mes essais).
Imports System.Collections.Generic

Public Class Environment
Public Property envName() As String
Public Property envHost() As String

Public Property Applications() As List(Of Application)

End Class

Public Class Application
Public Property appName() As String
Public Property appHost() As String
Public Property appComment() As String

Public Property Jobs() As List(Of Job)

End Class

Public Class Job
Public Property jobName() As String
Public Property jobHost() As String
Public Property jobComment() As String

Public Property Parameters() As List(Of String)
End Class


Pour la sub, j'ai ajouté le niveau Environnement :
            Dim maListe As List(Of Environment) = (
From el In xDoc.Descendants("Environment")
Select New Environment With {
.envName = CStr(el.Attribute("name").Value),
.envHost = CStr(el.Attribute("host").Value),
.Applications = (
From j In el.Descendants("Application")
Select New Application With {
.appName = j.Attribute("name").Value,
.appComment = j.Attribute("comment").Value,
.Jobs = (
From k In el.Descendants("Job")
Select New Job With {
.jobName = k.Attribute("name").Value,
.jobComment = k.Attribute("comment").Value
}).ToList()
}).ToList()
}).ToList()

Catch ex As Exception
TextBox2.Text = ex.Message
End Try


Options Explicit et Strict à On.
Aucune erreur mais maListe n'est pas reconnue par l'intellisense !!!

jean-marc
0
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 656
17 juin 2015 à 13:48
Bonjour,

Aucune erreur mais maListe n'est pas reconnue par l'intellisense !!!
c'est à dire?
0
cs_JMO Messages postés 1854 Date d'inscription jeudi 23 mai 2002 Statut Membre Dernière intervention 24 juin 2018 27
17 juin 2015 à 14:00
Bonjour Whismeril,

Avec
MessageBox.Show(maListe.Count)

j'obtiens
"Erreur 1 'maListe' n'est pas déclaré. Il peut être inaccessible en raison de son niveau de protection.

Idem avec For each

J'ai également essayé
            Dim maListe As List(Of Environment) = (
From el In xDoc.Descendants("Environment")
Select New Environment With {
.envName = CStr(el.Attribute("name").Value),
.envHost = CStr(el.Attribute("host").Value)
}).ToList()
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 656
17 juin 2015 à 14:44
La solution est probablement entre les lignes du message d'erreur.
Si tu l'as déclarée dans une méthode et que tu cherches à la lire dans une autre, elle n'est pas accessible.
Regarde ce principe


Public Class PortéeDesVariables'Attention jamais d'accent dans les noms de variables, classes, propriétés, etc, là c'est pour que l'exemple ne prête pas à confusion

'toute variable déclarée (pas forcément initialisée) ici est accessible de toute la classe
Dim variable1 as String

    Private Sub Quelconque1()
        Dim variable2 As Double 'accessible dans Sub Quelconque1 et ses sous blocs (boucle for.....)
        
        'ici je peux lire et écrire le contenu de variable1 et variable2 mais pas variable3
    End Sub   

    Private Sub Quelconque1()
        Dim variable3 As Double 'accessible dans Sub Quelconque1 et ses sous blocs (boucle for.....)
        
        'ici je peux lire et écrire le contenu de variable1 et variable3 mais pas variable2
    End Sub   
End Class


Il convient donc peut-être de déclarer
Dim maListe As List(Of Environment)
un cran au-dessus et l'initialiser dans la Sub
maListe = (From '.....
0
cs_JMO Messages postés 1854 Date d'inscription jeudi 23 mai 2002 Statut Membre Dernière intervention 24 juin 2018 27
Modifié par cs_JMO le 17/06/2015 à 16:30
j'ai
déclaré Private maListe As List(Of ENV)
renommé Public Class Environment en Public Class ENV car environment est un mot réservé

Avec
            maListe = (From el In xDoc.Descendants("Environment")
Select New ENV With {
.envName = CStr(el.Attribute("name").Value),
.envHost = CStr(el.Attribute("host").Value)
}).ToList()

maListe.Count me retourne 1 mais je n'arrive pas à lire son contenu !!!
Comment accéder aux variables envName et envHOST ???

        For Each test As ENV In maListe
TextBox2.Text = TextBox2.Text + test.envName.ToString + Environment.NewLine
TextBox2.Text = TextBox2.Text + test.envHost.ToString + Environment.NewLine
Next test

Est-ce la bonne méthode ???
0
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 656
17 juin 2015 à 20:17
Ben ça dépend de ce que tu veux faire, ce code semblerait mettre sur une ligne envName, puis sur la suivante envHost de chaque variable dans une texbox.

Je ne vois pas trop l'intérêt, autant se servir d'une listbox ou d'un datagridview.

Tu pourrais utiliser le binding.
Et mettre une propriété dans la classe Env qui sort directement le text au format que tu veux, ou overider la méthode ToString.

Je te poste un exemple plus tard.
0
cs_JMO Messages postés 1854 Date d'inscription jeudi 23 mai 2002 Statut Membre Dernière intervention 24 juin 2018 27
17 juin 2015 à 20:42
Pour l'environnement, j'ai besoin de la variable envHost, car si après dans la lecture de l'application la variable appHost n'existe pas, je dois récupérer envHost.
Idem pour la variable jobHost.

J'ai besoin de parcourir toutes les variables extraites pour modifier le contenu par plusieurs fonctions (beginTime = temps en secondes depuis 1970, d'autres remplacer "E" par "Execution", etc).

Exemple (issu de précédents tests):
           ' Variable Host
If appHost = Nothing Then
appHost = envHost
Else
appHost = CStr(xEle.Element("Applications").Element("Application").Attribute("host").Value)
End If
If jobHost = Nothing Then
jobHost = appHost
Else
jobHost = CStr(xEle.Element("Applications").Element("Application").Element("Jobs").Element("Job").Attribute("host").Value)
End If



Après manipulations, elles seront injectées dans un DataGridView.

Dans le post de 16h12-16h30, j'avais testé la query avec simplement l'environnement (ENV).

Avec le script ci-dessous, je ne sais pas comment "manipuler" la variable maListe.
        Try
maListe = (
From el In xDoc.Descendants("Environment")
Select New ENV With
{.envName = CStr(el.Attribute("name").Value),
.envHost = CStr(el.Attribute("host").Value),
.Applications = (
From j In el.Descendants("Application")
Select New APP With
{.appName = j.Attribute("name").Value,
.appHost = j.Attribute("host").Value,
.appComment = j.Attribute("comment").Value,
.Jobs = (
From k In el.Descendants("Job")
Select New JOB With
{.jobName = k.Attribute("name").Value,
.jobComment = k.Attribute("comment").Value
}).ToList()
}).ToList()
}).ToList()

Catch ex As Exception
TextBox2.Text = ex.Message
End Try
0
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 656
Modifié par Whismeril le 17/06/2015 à 21:46
J'ai besoin de parcourir toutes les variables extraites pour modifier le contenu par plusieurs fonctions


Alors peut-être faut-il déclarer les variables autrement dans la requête.

Tout d'abord un exemple avec plusieurs variantes dans la classe, pour les propriétés et pour l'initialisation

Imports System


    Public Class Personne
        Public Sub New() 'Constructeur vide, nécessaire si on veut initiliaser avec "les accolades"
        End Sub

        Public Sub New(ByVal Nom As String, ByVal Prenom As String, ByVal Naissance As Date) 'Constructeur avec paramètres
            Me.Nom = Nom
            Me.Prenom = Prenom
            Me.Naissance = Me.privateNaissance 'j'affecte la propriété comme ça l'age sera calculé
        End Sub

        Private privateNaissance As Date
        Public Property Naissance() As Date 'propriété avec calcul sur la variable interne
            Get
                Return privateNaissance
            End Get
            Set(ByVal value As Date)
                privateNaissance = value
                Age = Date.Now.Year - privateNaissance.Year
            End Set
        End Property

        Public Property Nom() As String

        Public Property Prenom() As String

        Public ReadOnly Property NomComplet() As String 'Propriété en lecture seule qui retourne le nom complet au format Prénom NOM
            Get
                Return String.Format("{0} {1}", Prenom, Nom.ToUpper())
            End Get
        End Property

        Private privateAge As Integer
        Public Property Age() As Integer 'Propriété en écriture interne uniquement
            Private Get
                Return privateAge
            End Get
            Set(ByVal value As Integer)
                privateAge = value
            End Set
        End Property

        Public Overrides Function ToString() As String 'Réécriture de la méthode ToString qui retourne l'initiale du Prénom.Nom
            Return String.Format("{0}.{1}", Prenom.Chars(0).ToString().ToUpper(), Nom.ToUpper())
        End Function

        Public Shared Function NouvellePersonne(ByVal Nom As String, ByVal Prenom As String, ByVal Age As Integer) As Personne 'méthode de classe pour une autre façon d'initialiser
            Return New Personne With {.Nom = Nom, .Prenom = Prenom, .Age = Age}
        End Function
    End Class


Et voilà comme faire 4 initialisations différentes
        Dim p1 As Personne = New Personne()'utilisation du constructeur vide, oblige ensuite d'initialiser les propriétés
        p1.Nom = "Dit"
        p1.Prenom = "Alain"
        p1.Naissance = DateTime.Parse("01/01/2000")

        Dim p2 As Personne = New Personne("Sors", "Jean", "01/02/2000")'hem constructeur

        Dim p3 As Personne = Personne.NouvellePersonne("Zètofrais", "Mélanie", 10)'Méthode de classe

        Dim p4 As Personne = New Personne With {.Nom = "Kenobi", .Prenom = "Ben"} 'De cette façon, on choisit quelles propriétés on intialise


Modérer m'amène à intervenir dans de nombreux posts, mais les seuls langages que je connaisses sont le C# et un peu de VB. Pour vos codes pensez à la coloration.
Réponse trouvée ->Question Résolue
0
cs_JMO Messages postés 1854 Date d'inscription jeudi 23 mai 2002 Statut Membre Dernière intervention 24 juin 2018 27
17 juin 2015 à 22:33
Merci pour cette Classe très explicite et documentée.
Etant un ex en vbs, je ne m'étais jamais aventuré dans les Property Get & Set. Je contournais cette utilisation par d'autres voies !!!
Je vais tester cette possibilité.

Néanmoins, je privilégie ta proposition de la méthode ToList().
Pour l'instant, mon principal problème est d'énumérer la variable maListe !!!

Quand ce souci sera résolu, je validerai ce post et poserai très certainement des questions via de nouveaux posts.

jean-marc
0
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 656 > cs_JMO Messages postés 1854 Date d'inscription jeudi 23 mai 2002 Statut Membre Dernière intervention 24 juin 2018
17 juin 2015 à 22:41
Ha je n'ai donc pas été assez explicité, dans la requête linq, pour initialiser la variable tu peux utiliser indifféremment l'une ou l'autre des méthode que je t'ai montrée.
Donc ma réponse précédente ne vient pas en contradiction des listes dans les listes, mais en complément.

De même, pour récupérer la variable Host du niveau en dessous si le niveau principal n'a pas été rempli, tu peux faire une propriété avec variable interne, au moment de l'interrogation (le get), si la variable est vide tu la rempli avec celle d'en dessous.
0
cs_JMO Messages postés 1854 Date d'inscription jeudi 23 mai 2002 Statut Membre Dernière intervention 24 juin 2018 27
Modifié par cs_JMO le 17/06/2015 à 23:15
Cet après-midi, avec la query
maListe = (From el In xDoc.Descendants("Environment")
Select New ENV With {
.envName = CStr(el.Attribute("name").Value),
.envHost = CStr(el.Attribute("host").Value)
}).ToList()
For Each test As ENV In maListe
TextBox2.Text = TextBox2.Text + test.envName.ToString + Environment.NewLine
TextBox2.Text = TextBox2.Text + test.envHost.ToString + Environment.NewLine
Next test

Les variables envName et envHost me renvoyaient correctement leur contenu.

Par contre, avec la query
            
maListe = (
From el In xDoc.Descendants("Environment")
Select New ENV With
{.envName = CStr(el.Attribute("name").Value),
.envHost = CStr(el.Attribute("host").Value),
.Applications = (
From j In el.Descendants("Application")
Select New APP With
{.appName = j.Attribute("name").Value,
.appHost = j.Attribute("host").Value,
.appComment = j.Attribute("comment").Value,
.Jobs = (
From k In el.Descendants("Job")
Select New JOB With
{.jobName = k.Attribute("name").Value,
.jobComment = k.Attribute("comment").Value
}).ToList()
}).ToList()
}).ToList()

Comment énumérer maList ???
0
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 656
Modifié par Whismeril le 17/06/2015 à 23:49
Les variables envName et envHost me renvoyaient correctement leur contenu.

Ce ne sont pas des variables, la variable (dans ta boucle for each) c'est test ; envName et envHost sont des propriétés de test.

Ensuite manifestement, on ne se comprend pas, ceci
For Each test As ENV In maListe
            TextBox2.Text = TextBox2.Text + test.envName.ToString + Environment.NewLine
            TextBox2.Text = TextBox2.Text + test.envHost.ToString + Environment.NewLine
        Next test
énumère maListe, les ToString sont inutiles car dans ta classe décrite au message 2, tu les a déclarés comme string.

Pour cette partie
J'ai besoin de parcourir toutes les variables extraites pour modifier le contenu par plusieurs fonctions (beginTime = temps en secondes depuis 1970, d'autres remplacer "E" par "Execution", etc).


Tu rentres d'une façon ou d'une autre la date et l'heure, et une autre propriété (en lecture seule peut-être) retourne ton beginTime, idem pour ton E à changer, dans le get de la propriété (ou dans un constructeur, ou un méthode Shared), si la valeur est E je mets Execution.

Comme ça la requête se contente de lire le fichier et de passer des données à des points d'entrée. Ces points d'entrée, eux savent quoi faire de ces données. On pourrait imaginer un constructeur, avec en paramètres les valeurs en string des éléments ou attributs ; ton constructeur trie les patates et convertit si besoin.

Si la requête est trop tordue, tu ne t'en sortiras pas.

Pour ça
j'ai besoin de la variable envHost, car si après dans la lecture de l'application la variable appHost n'existe pas, je dois récupérer envHost.
à la première lecture, je l'ai interprété à l'envers. Si pas de Host dans Environement, je prends celui de Job, donc je t'ai peut-être embrouillé.

Dans le bon sens, il y a deux solutions
  • 1 dans Application, tu as une propriété de type Environnement que tu appelle par exemple Parent.

Dans le get de Host de Application, si la variable interne est vide tu retournes Parent.Host
Cette solution est pratique, si dans Application tu as besoin d'accéder à plusieurs propriétés de l'Environnement. Voir
Pour remplir ce parent, il va falloir boucler sur chaque Job dans chaque Environnement avec des boucles ForEach imbriquées. Peut-être qu'on peut y arriver dans la requête, mais là ce soir, je suis fatigué et fais poser mon clavier à la fin de ce message ;-)
  • 2 Si tu ne penses pas avoir besoin de beaucoup de propriétés, de Environement et ou si le Host de Environnement peut ensuite varier sans que celui d'Application ne change une fois affecté, alors il faut copier la valeur, là encore avec des boucles imbriquées ou dans la requête (j'ai modifié vite fait mon premier code, si paramètre est vide je lui mais le nom de l'application et "Nom Application"

        Dim xDoc As XDocument = XDocument.Load("testJMO.xml")

        'je crée un tableau de 2 enregistrements que je caste en list pour la mettre dans le if à la place de Nothing
        Dim maListe As List(Of ApplicationJMO) = (
            From el In xDoc.Descendants("Application")
            Let noms As List(Of String) = {"NomApplication", el.Attribute("name").Value}.ToList()
            Select New ApplicationJMO With {
                .Name = el.Attribute("name").Value,
                .Jobs = (
            From j In el.Descendants("Job")
            Select New Job With
                   {
                       .Name = j.Attribute("name").Value,
                       .Retained = Convert.ToInt32(j.Attribute("retained").Value),
                       .Family = j.Attribute("family").Value,
                       .Script = j.Element("Script").ToString(),
                       .Parameters = If(j.Elements("Parameters").Count() = 0, noms, (
                        From p In j.Descendants("Parameter")
                        Select p.Value).ToList())
                   }).ToList()
                    }).ToList()





Modérer m'amène à intervenir dans de nombreux posts, mais les seuls langages que je connaisses sont le C# et un peu de VB. Pour vos codes pensez à la coloration.
Réponse trouvée ->Question Résolue
0
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 656
Modifié par Whismeril le 18/06/2015 à 18:25
Avant de détailler mon petit 1, et afin de ne pas partir dans une mauvaise direction, peux tu répondre à ces questions (à chaque fois je pars du principe que le Host de l'application n'est pas renseignée dans le fichier xml):
-Si le Host de l'environnement est modifié dans ton programme, doit-il l'être aussi dans la variable Application?
-Si j'affecte un autre Host à l'application, que devient celui de l'environnement?
-Est ce que tu réécris le fichier xml, si oui, que le Host de l'environnement doit-il être exporté, ou la ligne rester vide pour signifier que cette application n'a pas de host déterminé?
-Au final est-ce que tu souhaites manipuler une arboressence Env->Appli->Job ou une collection d'Appli qui savent remonter l'arborescence si nécessaire? (Par exemple si ton but est d'afficher les Appli dans un datagridview, la réponse est plutôt oui)

Je reviens vers toi ce soir.


Edit remise de l'arborescence dans le bon sens

Modérer m'amène à intervenir dans de nombreux posts, mais les seuls langages que je connaisses sont le C# et un peu de VB. Pour vos codes pensez à la coloration.
Réponse trouvée ->Question Résolue
0
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 656
Modifié par Whismeril le 18/06/2015 à 18:26
En complément de ma dernière question, Si Application doit savoir remonter son arborescence, préfère tu:
  • Job connait son Appli, Appli connait son Environnement
  • Job connait son Appli et son Environnement, et Appli s'en fout (au pire il regardera l'environnement d'un Job)
  • Job connait son Appli et son Environnement, Appli connait son Environnement


Edit remise de l'arborescence dans le bon sens
0
cs_JMO Messages postés 1854 Date d'inscription jeudi 23 mai 2002 Statut Membre Dernière intervention 24 juin 2018 27 > Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024
18 juin 2015 à 13:38
Bonjour Whismeril,

Structure du fichier (celui-ci est seulement en lecture)
<Domain name="DEV" stamp="VTEXPORT 5.6.4a FR LINUX_X64 2014/06/15">
<Environments>
<Environment name="exploitation" host="localhost">

<Applications>
<Application name="BASCULE_test_EXPLOIT" >

<Jobs>
<Job name="P9999H0102" retained="0" family="UNIX" comment="">
<Script><![CDATA#/opt/vtom/envoi.sh]></Script>
<Parameters>
<Parameter><![CDATA[TEST]]></Parameter>
</Parameters>
</Job>

<Job name="PBASCULEDATE" retained="0" family="TR1|UNIX" comment="Bascule">
<Script><![CDATA#/opt/vtom/test_bascule_exploitation.sh]></Script>
</Job>

</Jobs>

</Application>


<Application name="A-P9999H01" retained="0" comment="">

<Jobs>
<Job name="P9999H0101" retained="0" family="UNIX">

</Job>

</Jobs>
</Application>

</Applications>
</Environment>


<Environment name="production" host="172...">
.....
.....

</Environments>
</Domain>


Donc, dans chaque environnement, il y a plusieurs applications et dans chaque application, il y a un ou plusieurs jobs.

Action séquentielles:
Dans la balise <Environment name=>, il faut récupérer
- name="nom de l'environnement"
- host="nom du serveur".
name et host sont toujours présents dans cette balise.

Dans la balise <Application name=>, il faut récupérer
- name="nom de l'application"
- host="nom du serveur"
name est toujours présent
host n'est pas toujours présent donc host de l'application égal host de l'environnement

Dans la balise <Job name=>, il faut récupérer
- name="nom du job"
- host="nom du serveur"
name est toujours présent
host n'est pas toujours présent donc host du job host de l'application

Au final:

ENV APPLI HOST JOB

DEV APP1 local job1
DEV APP1 xxxx job2 ' xxxx car le job s'exécute sur un serveur distant
DEV APP1 local job3

DEV APP2 yyyy job1

PROD APP1 local job1
0
cs_JMO Messages postés 1854 Date d'inscription jeudi 23 mai 2002 Statut Membre Dernière intervention 24 juin 2018 27
18 juin 2015 à 13:46
Pour ma part, avec

Try
maListe = (
From el In xDoc.Descendants("Environment")
Select New ENV With {
.envName = el.Attribute("name").Value,
.envHost = el.Attribute("host").Value,
.Applications = (
From j In el.Elements("Application")
Select New APP With {
.appName = j.Attribute("name").Value,
.appHost = j.Attribute("host").Value,
.appComment = j.Attribute("comment").Value,
.Jobs = (
From k In el.Descendants("Job")
Select New JOB With {
.jobName = k.Attribute("name").Value,
.jobComment = k.Attribute("comment").Value
}).ToList()
}).ToList()
}).ToList()
Catch ex As Exception

Je n'ai pas d'erreur !!!

Avec

Try
For Each myENV As ENV In maListe
TextBox2.Text = TextBox2.Text & "envName" & _
Convert.ToChar(Keys.Tab) & myENV.envName + Environment.NewLine
TextBox2.Text = TextBox2.Text & "envHost" & _
Convert.ToChar(Keys.Tab) & myENV.envHost + Environment.NewLine
Next myENV
Catch ex As Exception

je liste correctement envName et envHost.
Par contre, je n'arrive pas à lister appName, appHost, jobName, jobHost ......

Par ailleurs, j'ai remplacé
From j In el.Descendants("Application")
par
From j In el.Elements("Application")
car j'avais une erreur

jean-marc
0
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 656
18 juin 2015 à 17:53
Ok, pas le temps de regarder là maintenant, mais tu n'as pas répondu à mes questions, qui ont leur importance sur ma réponse finale...
0
cs_JMO Messages postés 1854 Date d'inscription jeudi 23 mai 2002 Statut Membre Dernière intervention 24 juin 2018 27 > Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024
18 juin 2015 à 18:31
Appli connait son Job, Job connait son Environnement
Appli connait son Job et son Environnement, et Job s'en fout (au pire il regardera l'environnement d'une Appli)
Appli connait son Job et son Environnement,Job connait son Environnement
Non puisque la lecture du fichier est séquentielle


<Environments>
<Environment name="exploitation" date="date_exp" host="localhost">
'ici il faut créer 2 variables
'nameENV
'hostENV
<Applications>
<Application name="BASCULE_EXPLOIT" retained="0">
' ici on voit que l'appli n'a pas de host, on doit donc récupérer le host
' de l'environnement du name "exploitation", à savoir hostENV"
' ici je vais récupérer diverses variables de l'application name, retained '
' on va donc créer les variables
' nameAPP
' hostAPP
' etc, il y en a 8
'

<Jobs>
<Job name="PBASCULEDATE" retained="0" family="TR1|UNIX">
' ici on voit que le job n'a pas de host rattaché, il hérite du host de l'application. On doit donc récupérer le host de l'application, à savoir hostAPP.
' Si sur cette ligne il y a <Job name="xxxx' host="titi", on récupère titi pour hostJOB
' ici je vais récupérer diverses variables de l'application name, retained

' donc à ce niveau on dispose des variables
' nameENV
' nameAPP
' xxxxAPP
' yyyyAPP
' zzzzAPP
' nameJOB
'hostJOB
' familyJOB
' .... il y en a une vingtaine
' ces variables constitueront une ligne du datagridview sur x colonnes
' les variables hostENV et hostAPP ne seront pas écrites dans le datagridview puisque c'est le hostJOB qui sera récupéré


Tes exemples avec "myListe" me conviennent, mais comment parcourir la ToList()
0
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 656
18 juin 2015 à 21:15
Bon, je n'ai pas encore tous les éléments

-Si le Host de l'environnement est modifié dans ton programme, doit-il l'être aussi dans la variable Job? (idem pour celui de Application par rapport à Job)
pas de réponse

-Si j'affecte un autre Host au Job, que devient celui de l'environnement? (idem pour celui de Application par rapport à Job)


-Est ce que tu réécris le fichier xml?
tu dis lecture seule, donc j'en déduis que non, bien qu'on pourrait écrire un autre fichier

-Au final est-ce que tu souhaites manipuler une arboressence Env->Appli->Job ou une collection d'Appli qui savent remonter l'arborescence si nécessaire? (Par exemple si ton but est d'afficher les Appli dans un datagridview, la réponse est plutôt oui),
là aussi je déduis que oui.

0
cs_JMO Messages postés 1854 Date d'inscription jeudi 23 mai 2002 Statut Membre Dernière intervention 24 juin 2018 27
18 juin 2015 à 22:30
-Si le Host de l'environnement est modifié dans ton programme, doit-il l'être aussi dans la variable Job? (idem pour celui de Application par rapport à Job)

Le host de l'environnement est obligatoirement renseigné et non modifié.
Il doit être mémorisé.
Si le host d'une application (du même environnement) n'existe pas, on lui assigne le host de l'environnement courant.
Si le host d'un job (ou jobs) n'existe pas, on lui assigne le host de l'application courante. Celui-ci existe obligatoirement, car soit natif dans l'application, soit créé précédemment par le contrôle environnement/application.

-Si j'affecte un autre Host au Job, que devient celui de l'environnement? (idem pour celui de Application par rapport à Job)

Le host de l'environnement ne sers que si le host de l'appilcation n'est pas renseigné.
Le host de l'application courante doit être assigné au job n'ayant de host déclaré.

    -Est ce que tu réécris le fichier xml?

tu dis lecture seule, donc j'en déduis que non, bien qu'on pourrait écrire un autre fichier

Le fichier xml est en lecture seule.
Créer un fichier temp, pourquoi pas, mais à quoi servent ArrayList, Dictionary ou ListOf ?

-Au final est-ce que tu souhaites manipuler une arboressence Env->Appli->Job ou une collection d'Appli qui savent remonter l'arborescence si nécessaire? (Par exemple si ton but est d'afficher les Appli dans un datagridview, la réponse est plutôt oui),

Exemple du DataGridView
0
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 656
18 juin 2015 à 22:52
Alors je pense que ceci devrait t'aller

Avec ce xml
<Domain name="DEV" stamp="VTEXPORT 5.6.4a FR LINUX_X64 2014/06/15">
  <Environments>
    <Environment name="exploitation" host="localhost">
      <Applications>
        <Application name="BASCULE_test_EXPLOIT" >

          <Jobs>
            <Job name="P9999H0102" retained="0" family="UNIX" comment="">
              <Script><![CDATA[#/opt/vtom/envoi.sh]]></Script>
              <Parameters>
                <Parameter><![CDATA[TEST]]></Parameter>
              </Parameters>
            </Job>

          <Job name="PBASCULEDATE" retained="0" family="TR1|UNIX" comment="Bascule">
              <Script><![CDATA[#/opt/vtom/test_bascule_exploitation.sh]]></Script>
            </Job>

          </Jobs>

        </Application>


        <Application name="A-P9999H01" retained="0" comment="">

          <Jobs>
            <Job name="P9999H0101" retained="0" family="UNIX" host = "Host du Job">

            </Job>

          </Jobs>
        </Application>
      </Applications>
    </Environment>
  </Environments>
</Domain>



A chaque "étage", on connait le parent, qui permet si besoin de récupérer les champs du "dessus", pour le Host, mais aussi pour le nom de l'environnement pour l'affichage en Datagridview à la fin

Imports System.Collections.Generic

Public Class Job
    Public Property Name() As String

    Private privateHost As String
    Public Property Host() As String
        Get
            If String.IsNullOrWhiteSpace(privateHost) Then 'si mon host est vide, je retourne celui de mon parent
                Return parent.Host
            Else
                Return privateHost
            End If
        End Get
        Set(ByVal value As String)
            privateHost = value
        End Set
    End Property

    Private parent As ApplicationJMO

    Public ReadOnly Property EnvName() As String
        Get 'là je retourne directement le nom de l'environement, en lecture seule, si en cours d'exécution, celui=ci évolue, cette propriété sera à jour
            Return parent.Parent.Name
        End Get
    End Property

    Public Function AffecteParent(ByVal AppParent As ApplicationJMO, ByVal EnvParent As EnvironnementJMO) As Job 'cette métode permet d'affecter le parent tout en retourne un référence à l'instance en cours, elle servira à la 2eme requête
        parent = AppParent
        AppParent.Parent = EnvParent
        Return Me
    End Function
End Class

Public Class ApplicationJMO
    Public Property Name() As String

    Private privateHost As String
    Public Property Host() As String
        Get
            If String.IsNullOrWhiteSpace(privateHost) Then 'si mon host est vide, je retourne celui de mon parent
                Return Parent.Host
            End If
            Return privateHost
        End Get
        Set(ByVal value As String)
            privateHost = value
        End Set
    End Property

    Public Property Parent() As EnvironnementJMO

    Public Property Jobs() As List(Of Job)
End Class

Public Class EnvironnementJMO
    Public Property Name() As String

    Public Property Host() As String

    Public Property Applications() As List(Of ApplicationJMO)
End Class



Les 2 requêtes et le binding sur le datagridview
        Dim xDoc As XDocument = XDocument.Load("testJMO.xml")


        'Liste "copiée" sur l'arboressence
        Dim maListe As List(Of EnvironnementJMO) = (
            From e In xDoc.Descendants("Environment")
            Select New EnvironnementJMO With {.Name = e.Attribute("name").Value, .Host = e.Attribute("host").Value, .Applications = (
                    From a In e.Descendants("Application")
                    Select New ApplicationJMO With {.Name = a.Attribute("name").Value, .Host = If(a.Attributes("host").Count() > 0, a.Attribute("host").Value, Nothing), .Jobs = (
                            From j In a.Descendants("Job")
                            Select New Job With {.Name = j.Attribute("name").Value, .Host = If(j.Attributes("host").Count() > 0, j.Attribute("host").Value, Nothing)}).ToList()}).ToList()}).ToList()


        'liste de Jobs, avec les parents affectés
        Dim mesJobs As List(Of Job) = (
            From e In maListe, a In e.Applications, j In a.Jobs
            Select j.AffecteParent(a, e)).ToList()

        dataGridView1.DataSource = mesJobs


Et enfin le résultat




Le fichier xml est en lecture seule.
Créer un fichier temp, pourquoi pas, mais à quoi servent ArrayList, Dictionary ou ListOf ?
Je ne parlais pas d'un fichier temporaire, mais d'un fichier qui accueillerais les éventuelles modifications faites aux données par ton programme. C'est assez rares de juste vouloir lire des données, sans les trier, retoucher, etc...
0
cs_JMO Messages postés 1854 Date d'inscription jeudi 23 mai 2002 Statut Membre Dernière intervention 24 juin 2018 27
18 juin 2015 à 23:21
Merci Whismeril de ta persévérance.

Cela me fait penser à la maxime de Jacques.
Nul ne saurait valablement coder ce qu'il ne saurait exposer clairement.

Je vais d'abord analyser (comprendre avec MSDN car je suis new en .Net) et tester ton script avec un export xml complet d'une base.

Je ne parlais pas d'un fichier temporaire, mais d'un fichier qui accueillerais les éventuelles modifications faites aux données par ton programme. C'est assez rares de juste vouloir lire des données, sans les trier, retoucher, etc... 

Tu as bien compris, au parcours de ce thread, que j'ai besoin d'extraire d'autres informations (script, parametres ...).

Dans quel tutoriel ou bouquin, puis-je trouver, par exemple, l'explication de
Select j.AffecteParent(a, e)).ToList()


Je valide ce post et te remercie encore de ta contribution.

A+
jean-marc
0
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 656 > cs_JMO Messages postés 1854 Date d'inscription jeudi 23 mai 2002 Statut Membre Dernière intervention 24 juin 2018
18 juin 2015 à 23:58
Dans quel tutoriel ou bouquin, puis-je trouver, par exemple, l'explication de
Select j.AffecteParent(a, e)).ToList()

Je ne l'ai pas encore écrit 😉!

La clause select doit retourner un objet quelconque, si on reprend mon exemple des Personnes, si on veut une liste de prénoms, on dira au select de prendre le champ "Prenom" de la variable d'itération.

Car une requête n'est rien d'autre qu'une boucle foreach avec des options (groupement, jointure, etc....)

Donc comme j'avais besoin d'une part de tout itérér pour affecter le parent de chaque Job et chaque Application et de tout itérer de nouveau pour ne ressortir au final qu'une liste de Job, j'ai décidé (aussi en fonction de tes réponses, car ce choix pratique peut avoir des conséquences, surtout à l'export.....) d'écrire une méthode AffecteParent, prenant en paramètre l'Application en cours (a) et l'Environnement en cours (e), elle affecte le parent au Job en cours, le Grand Parent au Parent et retourne le Job en cours.

Attention cette méthode ne crée pas 2 listes séparées, mais deux vues des mêmes données, si tu changes quelque chose dans mesJob, ça le sera aussi dans maListe, c'est pour ça que j'ai bien insisté.
0
cs_JMO Messages postés 1854 Date d'inscription jeudi 23 mai 2002 Statut Membre Dernière intervention 24 juin 2018 27 > Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024
19 juin 2015 à 00:05
oui, j'ai bien vu !!!
Je vais renommer "e" car conflit avec les autres procédures.
J'analyse demain et te tiens au courant via de nouveaux posts.
0
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 656 > Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024
19 juin 2015 à 00:13
En fait, des listes dans des listes, ou un moment j'ai besoin de savoir qui est tout en haut, ça m'est déjà arrivé, là par exemple

Une autre fois, j'avais fait une gestion de championnat avec pour chaque championnat des manches et chaque manche des parties. Pour imprimer la feuille de partie, il fallait inscrire le championnat et la manche.

Ou encore, un calendrier, chaque année possède une liste de mois, chaque moi des semaines, chaque semaine des jours...

Mais ces exemples sont "petits", peut importe que tu fasses 50 boucles, les une derrières les autres, ça exécute très vite.

Pour le boulot, je dois traiter des fichiers de données, ou il y à quelques centaines de champs, et plusieurs centaines de milliers de lignes et il faut générer des courbes, là l'optimisation des requêtes (plus rapides que les boucle surtout si on ne force pas les ToList(), attention tout de même à l'exécution différée, c'est super et à la fois traitre) est importante.
0
cs_JMO Messages postés 1854 Date d'inscription jeudi 23 mai 2002 Statut Membre Dernière intervention 24 juin 2018 27
19 juin 2015 à 11:38
Bonjour Whismeril,

Comment afficher la colonne "Application" dans le DataGridView ???


jean-marc
0
cs_JMO Messages postés 1854 Date d'inscription jeudi 23 mai 2002 Statut Membre Dernière intervention 24 juin 2018 27
18 juin 2015 à 23:32
Relecture du thread,

Exemple du DataGridView

n'était pas une requête de ma part.
Souci pour inclure ma capture.
0
Rejoignez-nous