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

Scripts/Batch Discussion :

connaissez-vous le sujet 'Z'


Sujet :

Scripts/Batch

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert
    Avatar de I'm_HERE
    Homme Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 013
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Tunisie

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 013
    Par défaut connaissez-vous le sujet 'Z'
    salut,



    dans ce petit thread, on ne va rien faire, seulement connaitre le sujet 'Z' et surtout 'suivre son raisonnement'.

    le sujet 'Z' est un membre de DEV qui est entré dans le monde de PS et a maintenant un simple traitement à faire, qui se consiste à créer des élements 'doc' dans un fragement xml déja existant...suivant le:


    alors je commences par la bonne pratique:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    PS > Set-strictMode -version latest
    et maintenant on va charger notre fragment xml dans la mémoire.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    PS > $docX = [xml] @'
     <docs>
       <doc>doc 1</doc>
       <doc>doc 2</doc>
       <doc>doc 3</doc>
       <doc>doc 4</doc>
     </docs>
    '@
    c'est simple comme tout et maintenant on va selectionner les noeuds 'doc'

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    PS > $docs = $docX.GetElementsByTagName('doc')
    je comptes les objets de cette collection:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    PS > $docs.length
    
    La propriété «*length*» est introuvable sur cet objet. Vérifiez qu'elle existe.
    Au niveau de ligne*: 1 Caractère*: 7
    + $docs. <<<< length
        + CategoryInfo          : InvalidOperation: (.:OperatorToken) [], RuntimeE
       xception
        + FullyQualifiedErrorId : PropertyNotFoundStrict
    mais qu'est-ce qui se passe ? ou est donc passé la propriété 'length' qui est une propriété-Alias pour les types de base System.Array comme est decrit dans le fichier de configuration:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    PS D:\> cat $pshome/types.ps1xml | Select-String "system.array" -co 0,6
    
    >         <Name>System.Array</Name>
              <Members>
                  <AliasProperty>
                      <Name>Count</Name>
                      <ReferencedMemberName>Length</ReferencedMemberName>
                  </AliasProperty>
              </Members>

    voyant le premier element:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    PS> $docs[0]
    Impossible d'indexer dans un objet de type System.Xml.XmlElementList.
    Au niveau de ligne*: 1 Caractère*: 7
    + $docs[ <<<< 0]
        + CategoryInfo          : InvalidOperation: (0:Int32) [], RuntimeException
        + FullyQualifiedErrorId : CannotIndex
    et en plus ça ne s'indexe pas ?!

    je vais essayer avec une autre manière:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    PS> $docs |select -first 1 -expand '#text'
    doc 1
    le message d'erreur mentionne que le type System.Xml.XmlElementList ne peux pas être indexé, ou du moins de cette manière, car au final c'est une liste et une liste doit pouvoir être indexé d'une facon ou d'une autre.

    je vais chercher les membres de cette collection 'XmlElementList':

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    PS> get-member -input $docs
    ....
    ....
    Item          Method                System.Xml.XmlNode Item(int index)
    Count         Property              System.Int32 Count {get;}

    j'essayes avec la propriété Count

    et maintenant la méthode 'Item'

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    PS> $docs.item(0).innertext
    doc 1

    donc, cette collection n'est pas une simple liste et à ce que je vois System.Array n'est pas son type de base.
    Comme beaucoup d'objet COM on ne peux pas acceder a ses elements qu'avec la méthode item()

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    PS > # exemple
    PS > $comobject = New-Object -ComObject WScript.shell
    PS > $spf = $comobject.SpecialFolders
    PS > $spf[0]
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Impossible d'indexer dans un objet de type System.__ComObject.
    Au niveau de ligne*: 1 Caractère*: 6
    + $spf[ <<<< 0]
        + CategoryInfo          : InvalidOperation: (0:Int32) [], RuntimeException
        + FullyQualifiedErrorId : CannotIndex

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    PS > $spf.Item(0)
    D:\Documents and Settings\All Users\Bureau

    je continue maintenant mon traitement, on veux ajouter d'autres elements 'doc' au fragment xml $docX au nombre des 'doc' déja existant, ici on a 4 elements 'doc' donc il faut ajouter 4 autres 'doc' pour que le resultat devienne au final:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     <docs>
       <doc>doc 1</doc>
       <doc>doc 2</doc>
       <doc>doc 3</doc>
       <doc>doc 4</doc>
       <doc>doc 5</doc>
       <doc>doc 6</doc>
       <doc>doc 7</doc>
       <doc>doc 8</doc>
     </docs>
    je crois que je vais utiliser une boucle 'for'

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    for($i=0; $i -lt $docs.count; $i++) {
       $child = $docX.CreateElement("doc")
       $child.innerText = "doc $($docs.count + 1)"
       $nul=$docX.docs.appendChild($child)
       write-verbose "ajout de $($child.OuterXml)" -verbose
    }
    mais qu'es-ce qui se passe ? c'est une boucle infini !!
    en théorie elle va nous ajouter un nombre défini d'elements 'doc' (ici 4) mais en réalité c'est une boucle infini.

    en réalité une collection DOM XmlElementList est une collection "vivante" c'est à dire qu'elle se mets à jour automatiquement si le document change, elle n'est pas donc statique comme les autres collections, de ce fait "$docs.count" s'incremente à chaque ajout de nouveaux elements 'doc', donc la loupe devient une loupe infini.

    comment remdier à ce problème ?

    je vais essayer de mettre le contenu du '$docs.count' dans une variable en dehors du contexte de la loupe, ainsi, je crois, que la collection sera mise à jour une seul fois à la fin de la boucle.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    PS > $docX = [xml] @'
     <docs>
       <doc>doc 1</doc>
       <doc>doc 2</doc>
       <doc>doc 3</doc>
       <doc>doc 4</doc>
     </docs>
    '@
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    $docs = $docX.GetElementsByTagName('doc')
    
    $len = $docs.count
    for($i=0; $i -lt $len; $i++) {
       $child = $docX.CreateElement("doc")
       $child.innerText = "doc $($docs.count + 1)"
       $nul=$docX.docs.appendChild($child)
       write-verbose "ajout de $($child.OuterXml)" -verbose
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    PS > $docX.CreateNavigator().OuterXml
    
    <docs>
      <doc>doc 1</doc>
      <doc>doc 2</doc>
      <doc>doc 3</doc>
      <doc>doc 4</doc>
      <doc>doc 5</doc>
      <doc>doc 6</doc>
      <doc>doc 7</doc>
      <doc>doc 8</doc>
    </docs>
    Bingo !!

    au final le sujet 'Z' a resolu son probléme après quelques tests et recherches..

    Remarque:
    l'utilisation des proprités d'objets dans le contexte d'une boucle est une mauvaise pratique comme l'a montré ce thread, j'ai voulu vous montré qu'en plus du problème de performance il y a aussi un problème de mise à jour des collections vivantes du DOM.

  2. #2
    Membre Expert
    Avatar de sachadee
    Homme Profil pro
    AMI DU BAT
    Inscrit en
    Janvier 2013
    Messages
    1 478
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Brésil

    Informations professionnelles :
    Activité : AMI DU BAT
    Secteur : Distribution

    Informations forums :
    Inscription : Janvier 2013
    Messages : 1 478
    Par défaut
    Salut I'm Here et merci !

  3. #3
    Rédacteur


    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    7 171
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 7 171
    Billets dans le blog
    1
    Par défaut
    Bonjour Walid,
    une remarque sur :
    Citation Envoyé par I'm_HERE Voir le message
    ...elle n'est pas donc statique comme les autres collections...
    Je ne suis pas certains que ta formulation soit correcte :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    $T=new-object System.Collections.ArrayList 
    $null=1..4|% {$T.add($_)}
    For($i=0; $i -lt $T.Count; $i++) {
       $nul=$T.Add($i)
       write-verbose "ajout de $i" -verbose
    }
    
    $T=1..4 
    for($i=0; $i -lt $T.Count; $i++) {
       $T +=$i
       write-verbose "ajout de $i" -verbose
    }
    Les deux cas ont le même problème.

    Ici,bien que l'exemple manque de sens, PS est plus stricte :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    $docX.GetElementsByTagName('doc')|
     Foreach {
       $child = $docX.CreateElement("doc")
       $child.innerText = "doc $($docX.GetElementsByTagName('doc').Count + 1)"
       $nul=$docX.docs.appendChild($child)
       write-verbose "ajout de $($child.OuterXml)" -verbose
    }
    #<position> : Une erreur s'est produite lors de l'énumération parmi une collection : La liste d'éléments a changé.
    # Échec de l'opération d'énumération..
    Et comme il y a déjà 4 version de PS tu devrais préciser laquelle tu utilises.
    Post à classer dans les 'gotcha'/piéges

  4. #4
    Membre Expert
    Avatar de I'm_HERE
    Homme Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 013
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Tunisie

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 013
    Par défaut
    salut sachadee, Laurent

    Citation Envoyé par Laurent Dardenne Voir le message

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    for($i=0; $i -lt $docs.count; $i++) {
       $child = $docX.CreateElement("doc")
       $child.innerText = "doc $($docs.count + 1)"
       $nul=$docX.docs.appendChild($child)
       write-verbose "ajout de $($child.OuterXml)" -verbose
    }
    #############################

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    $T=new-object System.Collections.ArrayList 
    $null=1..4|% {$T.add($_)}
    For($i=0; $i -lt $T.Count; $i++) {
       $nul=$T.Add($i)
       write-verbose "ajout de $i" -verbose
    }
    Les deux cas ont le même problème.
    en fait, il y a une certaine "ambiguite" dans les deux cas, je ne sais pas si ce terme est adéquate pour décrire ceci: dans mon exemple c'est le DOM qui se met à jour à chaque changement du document, donc c'est plus spécifique à PS mais à tout langage traitant avec le DOM, dans ton exemple c'est le dynamisme de PS, donc dans ton cas c'est plus spécifique au langage même.

    Citation Envoyé par Laurent Dardenne Voir le message
    Et comme il y a déjà 4 version de PS tu devrais préciser laquelle tu utilises.
    malheureusement encore avec la V2

  5. #5
    Rédacteur


    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    7 171
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 7 171
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par I'm_HERE Voir le message
    en fait, il y a une certaine "ambiguite" dans les deux cas
    Je te parlais de l'usage de la notion de 'statique' qui n'est pas adapté au contexte.
    Tout comme l'usage du terme "vivant", mutable/immutable est peut être plus approprié.
    Citation Envoyé par I'm_HERE Voir le message
    dans mon exemple c'est le DOM qui se met à jour à chaque changement du document, donc c'est plus spécifique à PS
    J'ai un doute, il me semble que c'est plus le framework qui est concerné ici que l'implémentation de PS, en tout cas sur ce point.
    Citation Envoyé par I'm_HERE Voir le message
    malheureusement encore avec la V2
    De mon côté je code le plus souvent en V2, car c'est le cas pour de nombreuses entreprises.
    Tu peux installer la V3, car tu disposeras tjr du moteur de la V2 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -version 2.0
    Avec la v4, le moteur de la v2 reste accessible, mais pas celui de la v3.

    Sinon, sur le sujet, il existe aussi l'approche autour de Foreach.

  6. #6
    Membre Expert
    Avatar de I'm_HERE
    Homme Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 013
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Tunisie

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 013
    Par défaut
    salut Laurent,

    Citation Envoyé par Laurent Dardenne Voir le message
    Tu peux installer la V3, car tu disposeras tjr du moteur de la V2 :
    %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -version 2.0
    malheureusement, je ne peux pas...j'ai une machine trop vieille...en attendant que j'achète une autre...plus adéquate surtout pour les tests.



    Citation Envoyé par Laurent Dardenne Voir le message
    Avec la v4, le moteur de la v2 reste accessible, mais pas celui de la v3.
    merci pour l'info, je ne le savais pas.

Discussions similaires

  1. [Clarion] Connaissez vous ?
    Par lil_jam63 dans le forum Autres langages
    Réponses: 3
    Dernier message: 09/10/2008, 15h42
  2. Connaissez vous SAPdb
    Par XavierZERO dans le forum SAP
    Réponses: 4
    Dernier message: 29/01/2007, 23h32
  3. Quel site connaissez-vous pour la physique ?
    Par dips dans le forum Physique
    Réponses: 5
    Dernier message: 02/06/2004, 16h17
  4. Connaissez vous un routeur pour ...
    Par loki dans le forum Développement
    Réponses: 3
    Dernier message: 18/09/2002, 09h05
  5. [langage] connaissez-vous autre chose que -d
    Par Sébastien dans le forum Langage
    Réponses: 4
    Dernier message: 05/08/2002, 20h13

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