Hé, vous le scripteur !Derniers mots célèbres

Les scripteurs Microsoft

Socrate, célèbre philosophe grec (mort en 399 av. J.-C., juste avant la naissance de notre Rédacteur en chef), est peut-être mieux connu pour la citation suivante : « Une vie sans examen ne vaut pas la peine d’être vécue ». La plupart des gens connaissent cette citation. Récemment, toutefois, les scripteurs ont découvert que Socrate n'avait jamais affirmé qu'« une vie sans examen ne vaut pas la peine d’être vécue ». Il s'avère en fait qu'un scribe du Moyen-Âge a mal traduit les paroles du philosophe il y a plusieurs centaines d'années. Voici ce que Socrate a réellement dit : « Un fichier XML sans examen ne vaut pas la peine d’être possédé ».

Voilà enfin une citation philosophique qui a du sens ! Le format XML est de plus en plus répandu ces jours-ci ; une recherche rapide effectuée sur l'un des ordinateurs de test des scripteurs a permis de découvrir plus de 500 fichiers XML utilisés par divers systèmes ou applications.

Inutile de dire que de grandes quantités de données très importantes sont maintenant stockées au format XML. Et c'est très bien. Sauf si ces données ne font l'objet d'aucun examen. Malheureusement, il en va souvent ainsi, ne serait-ce que pour la raison suivante : la plupart des gens ne savent absolument pas pas comment examiner un fichier XML. En particulier, ils n'ont aucune idée de la façon d'interroger et d'effectuer des recherches sur ce fichier XML.

Remarque : Au cas où vous ne connaîtriez pas bien vos philosophes grecs, Socrate aimait discuter de tout, mais il était plutôt partisan du moindre effort ; en fait, Xanthippe, sa femme, disait qu'il était « un bon à rien ». On comprend donc pourquoi les scripteurs ont un petit faible pour Socrate.

Bien sûr, certains d'entre vous diront : « Un instant ! Les scripteurs n'ont-ils pas déjà abordé le sujet de la recherche de fichiers XML dans un article précédent (« La chasse aux voitures... et le XML » à technet.microsoft.com/magazine/cc162506) ? Dans ce cas, pourquoi reviennent-ils sur ce sujet maintenant ? Les scripteurs sont-il si paresseux qu'ils sont prêts à écrire le même article plusieurs fois » ?

Eh bien, croyez-le ou non, nous sommes encore plus paresseux que cela ! Toutefois, ce n'est pas la raison principale pour laquelle nous revenons sur ce sujet. Dans notre article précédent, nous avons examiné l'utilisation d'un fichier XML structuré comme le code de la figure 1, où chaque valeur de propriété représente un seul nœud dans le fichier.

Figure 1 Fichier XML avec nœuds seulement

<?xml version='1.0'?> 
  <INVENTORY> 
    <COMPUTER>
      <os>Windows XP</os>
      <department>Human Resources
      </department>
      <name>atl-ws-001</name>
    </COMPUTER> 
    <COMPUTER>
      <os>Windows XP</os>
      <department>Finance</department>
      <name>atl-ws-002</name>
    </COMPUTER> 
    <COMPUTER>
      <os>Windows Vista</os>
      <department>Finance</department>
      <name>atl-ws-003</name>
    </COMPUTER> 
  </INVENTORY>

Toutefois, et comme nous l'on gentiment fait remarquer certaines personnes, ce n'est pas la seule façon de structurer les fichiers XML. Dans l'exemple précédent, chaque ordinateur du fichier a son propre nœud ; chacun de ces nœuds a à son tour plusieurs nœuds enfants (système d'exploitation, département et nom). Cependant, il est également possible de construire un fichier XML dans lequel les nœuds individuels n'ont pas de nœuds enfants ; au lieu de cela, des valeurs de propriété supplémentaires sont configurées en tant qu'attributs. Exactement comme le fichier de la figure 2 !

Figure 2 Fichier XML avec attributs

<?xml version='1.0'?> 
  <HARDWARE> 
      <COMPUTER os="Windows XP" department="Human Resources">atl-ws-001</COMPUTER> 
      <COMPUTER os="Windows XP" department="Finance">atl-ws-002</COMPUTER> 
      <COMPUTER os="Windows Server 2003" department="IT">atl-fs-003</COMPUTER> 
      <COMPUTER os="Windows Vista" department="IT">atl-ws-004</COMPUTER> 
      <COMPUTER os="Windows Vista" department="Human Resources">atl-ws-005</COMPUTER> 
      <COMPUTER os="Windows Vista" department="Finance">atl-ws-006</COMPUTER> 
      <COMPUTER os="Windows XP" department="Sales">atl-ws-007</COMPUTER> 
      <COMPUTER os="Windows Server 2008" department="IT">atl-fs-008</COMPUTER> 
      <COMPUTER os="Windows XP" department="Human Resources">atl-ws-009</COMPUTER> 
      <COMPUTER os="Windows Vista" department="Sales">atl-ws-010</COMPUTER> 
  </HARDWARE>

Cela pose-t-il un problème ? Eh bien, en fait, oui ! Le script que nous vous avons montré il y a longtemps, dans un vieux numéro, ne fonctionnera pas avec un fichier XML structuré comme à la figure 2. C'est tout simplement impossible ! Et ça, c'est un vrai problème parce qu'un grand nombre d'entre vous ont besoin de pouvoir lire ce type de fichier XML.

Il vous suffisait de le demander. Et aussi d'attendre un an et demi, le temps que nous nous attelions enfin à résoudre ce problème.

Avant de continuer, examinons notre fichier XML de plus près. Dans ce cas, nous avons un fichier avec un nœud principal appelé HARDWARE ; chaque ordinateur individuel existe en tant que nœud enfant de HARDWARE. En outre, chacun de ces nœuds a une paire d'attributs : os (utilisé pour stocker le nom du système d'exploitation installé sur l'ordinateur) et department (utilisé pour stocker le nom du service qui possède l'ordinateur).

Supposons, par exemple, que nous aimerions obtenir une liste de tous les ordinateurs qui exécutent Windows XP. Pouvons-nous le faire à l'aide d'un script ? Bien sûr que oui :

Set xmlDoc = _
  CreateObject("Microsoft.XMLDOM")

xmlDoc.Async = "False"
xmlDoc.Load("HARDWARE.xml")

Set colNodes=xmlDoc.selectNodes _
  ("//HARDWARE/COMPUTER[@os='Windows XP']")

For Each objNode in colNodes
  Wscript.Echo objNode.Text 
Next

Voyons ce que nous avons là. Pour commencer, nous créons une instance de l'objet Microsoft.XMLDOM ; comme son nom l'indique, il s'agit de l'objet qui nous permet d'utiliser les fichiers XML. Une fois que nous avons créé l'objet, nous définissons la propriété Async sur False ; cela dit au script que nous voulons charger le document d'une manière synchrone et non pas asynchrone. Pourquoi le script s'en soucie-t-il ? Pour être honnête, il n'en a probablement cure ; après tout, les scripts (comme les scripteurs) sont des objets inanimés.

Toutefois, vous devez vous en soucier, vous. Si nous chargions le document de manière asynchrone, le script continuerait à s'exécuter même si le document n'avait pas été entièrement chargé. Et cela n'irait pas du tout : imaginez les problèmes qui pourraient survenir si vous essayiez d'exécuter une tâche sur un document qui n'existe pas encore. Le chargement asynchrone d'un fichier XML garantit que le fichier sera entièrement chargé avant le démarrage du script.

Étrange coïncidence, nous en sommes maintenant au point où nous allons charger notre fichier XML, ce que nous faisons en appelant la méthode Load et en ouvrant le fichier C:\Scripts\HARDWARE.xml qui nous amène à cette ligne de code :

Set colNodes=xmlDoc.selectNodes _
  ("//HARDWARE/COMPUTER[@os='Windows XP']")

Nous utilisons ici la méthode SelectNodes pour interroger le fichier XML et indiquer au script les nœuds XML que nous voulons récupérer. Remarquez la syntaxe, qui, il est vrai, est un peu inhabituelle.

Pour commencer, nous devons spécifier le chemin dans le fichier XML. Notre fichier XML a un nœud de premier niveau appelé HARDWARE, suivi par une série de nœuds de deuxième niveau appelés COMPUTER. Chacun de ces nœuds de deuxième niveau représente un enregistrement unique dans notre fichier de données XML. C'est pourquoi notre requête selectNodes commence ainsi :

//HARDWARE/COMPUTER

À ce stade, nous rencontrons la construction suivante :

[@os='Windows XP']

Cette section de la requête est identique à une clause WHERE dans une requête SQL standard. Avec SQL, nous pourrions utiliser une requête de base de données identique à la suivante pour récupérer une liste de tous les ordinateurs exécutant le système d'exploitation Windows XP :

SELECT Name FROM Hardware 
    WHERE OS = 'Windows XP'

Avec la méthode SelectNodes nous faisons quelque chose de similaire : nous souhaitons récupérer une liste de tous les ordinateurs où l'attribut du système d'exploitation (@os) est égal à Windows XP, et pour indiquer qu'il s'agit d'une clause WHERE, nous incluons la clause toute entière entre crochets.

Remarque : ce type de requête est appelé requête XPath. Pour en savoir plus sur XPath, consultez l'article à l'adresse msdn.microsoft.com/library/ms256115.aspx.

Comme je le disais donc, c'est bizarre, mais ça marche. Mais qu'en serait-il si nous voulions obtenir une liste de tous les ordinateurs qui appartiennent au service Finances ? Ce n'est pas très compliqué : notre appel à selectNodes ressemblerait à ceci :

Set colNodes=xmlDoc.selectNodes _
  ("//HARDWARE/COMPUTER" & _
   "[@department='Finance']")

Là aussi, notre clause WHERE est incluse entre crochets, nous faisons précéder le nom d'attribut (department) de l'arobase (@) et nous indiquons la valeur qui nous intéresse.

Facile, non ?

Après avoir appelé la méthode selectNodes, nous pouvons renvoyer les noms d'ordinateur simplement en effectuant une boucle à travers la collection de valeurs renvoyées et en renvoyant la propriété Text, comme suit :

For Each objNode in colNodes
  Wscript.Echo objNode.Text 
Next

Et qu'elle genre d'informations pourrions-nous recevoir ? À vrai dire, nous espérons recevoir des informations de ce type :

atl-ws-001
atl-ws-002
atl-ws-007
atl-ws-009

En d'autres termes, ce sont les noms de tous les ordinateurs qui exécutent toujours Windows XP qui sont renvoyés.

Notez que vous n'êtes pas obligé de ne renvoyer que le nom de l'ordinateur ; dans la mesure où le nom de l'ordinateur est la valeur par défaut de chaque nœud, c'est la valeur que nous recevons si nous référençons la propriété Text.

Nous pourrions également spécifier exactement les valeurs d'attribut que nous souhaitons récupérer. Par exemple, jetons un coup d'œil sur cette boucle For Each modifiée :

For Each objNode in colNodes
    Wscript.Echo objNode.Text 
    Wscript.Echo objNode.Attributes. _
      getNamedItem("department").Text
    Wscript.Echo
Next

Comme vous le voyez, dans cette boucle, nous continuons à renvoyer la valeur de la propriété Text ; cependant, nous avons également ajouté cette ligne de code :

Wscript.Echo objNode.Attributes. _
  getNamedItem("department").Text

Dans ce cas, nous utilisons la méthode getNamedItem pour récupérer la valeur de l'attribut department ; nous renvoyons ensuite la propriété Text de cet attribut. Voilà comment nous pouvons spécifier les valeurs d'attribut que nous renvoyons (et ne renvoyons pas) à l'écran. (Remarquez aussi que nous avons ajouté une commande Wscript.Echo pour placer une ligne vide entre les enregistrements). À l'exécution ce script, nous devrions recevoir ce qui suit :

atl-ws-001
Human Resources

atl-ws-002
Finance

atl-ws-007
Sales

atl-ws-009
Human Resources

Et oui, vous pouvez écrire des requêtes plus complexes si vous le souhaitez. Par exemple, supposons que vous souhaitiez avoir une liste de tous les ordinateurs exécutant Windows XP ou Windows Vista. Dans SQL, vous obtenez cette liste en écrivant une requête OR. Et devinez un peu ? Vous faites exactement la même chose lorsque vous interrogez un fichier XML :

Set colNodes=xmlDoc.selectNodes _
    ("//HARDWARE/COMPUTER" & _
     "[@os='Windows XP' or " & _
     "@os='Windows Vista']")

Vous voyez ce que nous venons de faire ici ? Dans une seule paire de crochets, nous avons fourni deux critères : @os='Windows XP' ou @os='Windows Vista'. C'est tout ce que nous devons faire, et nous obtiendrons ainsi un rapport qui ressemble à la figure 3.

Figure 3 Résultat de la requête OR

atl-ws-001
Human Resources

atl-ws-002
Finance

atl-ws-004
IT

atl-ws-005
Human Resources

atl-ws-006
Finance

atl-ws-007
Sales

atl-ws-009
Human Resources

atl-ws-010
Sales

Si vous réexaminez le fichier XML, vous verrez que les ordinateurs exécutant Windows XP ou Windows Vista sont inclus dans la sortie ; les ordinateurs exécutant Windows Server 2003 ou Windows Server 2008 ne sont pas inclus dans la sortie, ce qui est tout à fait normal.

Vous avez une question ? Vous aimeriez écrire une requête plus limitée qui renvoie seulement les ordinateurs qui s'exécutent Windows XP et qui appartiennent au service Finances ? Comme vous l'avez peut-être deviné, c'est très facile : il vous suffit d'écrire une requête AND comme suit :

Set colNodes=xmlDoc.selectNodes _
    ("//HARDWARE/COMPUTER" & _
     "[@os='Windows XP' and " & _
     "@department='Finance']")

Vous recevez ainsi le jeu de données suivant :

atl-ws-002
Finance

Pourquoi y a-t-il seulement un élément dans notre rapport ? Exactement : c'est parce que le service Finances ne possède qu'un seul ordinateur qui exécute Windows XP.

Nous espérons que nous vous avons tous aidés à traiter ce type de fichier XML. S'il s'avère qu'il existe un autre type de fichier XML quelque part, hé bien, bonne chance !

Comme nous avons commencé cet article avec une citation célèbre, nous aimerions le conclure par une autre citation, celle de l'empereur Guillaume II, qui nous est chère à nous autres, scripteurs : « Par la présente, je renonce pour toujours au trône de Prusse et à celui de l'Allemagne impériale qui lui est associé. ».

Les scripts embrouillés du Dr. Scripto

Le défi mensuel qui teste non seulement votre capacité à résoudre des énigmes, mais également vos compétences d'écriture de scripts.

Octobre 2008 : VBScript Faites le plein

Pour résoudre cette énigme, il vous suffit de remplir chaque ligne avec le nom d'une fonction VBScript. Ensuite, remettez les lettres des carrés bleus dans l'ordre pour trouver un autre nom de fonction.

fig10.gif

RÉPONSE :

Les scripts embrouillés du Dr. Scripto

Réponse : Octobre 2008 : VBScript Faites le plein

puzzle_answer.gif

Les scripteurs—Greg Stemp et Jean Ross—travaillent pour Microsoft.