Hey, Scripting Guy!Le ultime parole famose

Microsoft Scripting Guys

Il famoso filosofo greco Socrate (che morì nel 399 a.C., poco prima che nascesse l'editor di script) è noto per aver affermato che "una vita senza ricerca non vale la pena di essere vissuta". La maggior parte degli utenti conoscerà questo detto. Tuttavia, di recente gli Scripting Guy hanno rivelato, con grande stupore, che Socrate non ha mai pronunciato tali parole. Sembra, infatti, che si tratti di un errore di traduzione commesso da uno scriba medievale centinaia di anni fa. La frase che Socrate pronunciò in realtà è: "Non vale la pena avere un file XML non esaminato".

Questa sì che è una massima filosofica che ha senso! Ultimamente, il formato XML sta acquisendo sempre più popolarità: da una rapida ricerca eseguita sul computer di prova di uno degli Scripting Guy sono risultati oltre 500 file XML utilizzati da diversi sistemi o applicazioni.

Inutile dire che, oggi, una grande quantità di dati importanti è memorizzata in formato XML, senza che questo crei problemi, a patto che, ovviamente, i dati siano esaminati. Purtroppo, ciò non accade spesso, se non altro, perché molti utenti non hanno la benché minima idea di come esaminare un file XML. In particolare, non hanno idea di come eseguire una query e una ricerca all'interno di file di questo tipo.

Nota: per chi non se ne intende di filosofi greci, Socrate era un grande sostenitore del dialogo, ma non sosteneva con altrettanto fervore l'azione; infatti, sua moglie, Santippe, lo chiamava "pigro buono a nulla". Ora è chiaro il motivo per cui gli Scripting Guy hanno un debole per Socrate.

Naturalmente, qualche lettore a questo punto potrebbe pensare: "Aspetta un attimo: gli Scripting Guy non si sono già occupati della ricerca nei file XML in un articolo precedente ("Inseguire automobili... e XML" all'indirizzo technet.microsoft.com/magazine/cc162506)? Se è così, perché hanno deciso di ritornare sull'argomento? Sono talmente pigri che riscriveranno lo stesso articolo all'infinito?"

Si creda o no, siamo anche più pigri di così. Tuttavia, questo non è il motivo primario per cui stiamo riprendendo l'argomento. Nell'articolo precedente si illustrava l'utilizzo di un file XML con una struttura simile al codice riportato nella Figura 1, in cui ciascun valore della proprietà rappresentava un nodo all'interno del file.

Figura 1 File XML solo con nodi

<?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>

Si tratta di una struttura efficiente, tuttavia, come alcuni lettori hanno prontamente sottolineato, non è l'unica di cui un file XML può disporre. Nell'esempio precedente ogni computer nel file ha il proprio nodo; a sua volta, ciascuno dei nodi ha numerosi nodi figlio (sistema operativo, reparto e nome). Tuttavia, è anche possibile costruire un file XML in cui i singoli nodi non abbiano nodi figlio: in questo caso, i valori aggiuntivi delle proprietà sono configurati come attributi, come nel file nella Figura 2.

Figura 2 File XML con attributi

<?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>

Questo è un problema? In effetti, sì. Lo script illustrato in un numero di molto tempo fa non funziona con un file XML strutturato come quello illustrato nella Figura 2. Non può funzionare e questo è indubbiamente un problema, poiché molti degli utenti devono poter leggere questo tipo di file XML.

Bene, bastava chiedere. O meglio, chiedere e aspettare un anno e mezzo prima che riuscissimo finalmente a occuparci di questo problema.

Prima di proseguire, si esaminerà nel dettaglio il file XML. In questo caso il file contiene un nodo primario denominato HARDWARE e ogni singolo computer esiste sotto forma di nodo figlio di HARDWARE. Inoltre, ciascuno dei nodi ha una coppia di attributi: os (utilizzato per memorizzare il nome del sistema operativo installato sul computer) e department (utilizzato per memorizzare il nome del reparto cui appartiene il computer).

Si supponga, ad esempio, di voler ottenere un elenco di tutti i computer che utilizzano Windows XP. È possibile farlo utilizzando uno script? Ovviamente sì:

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

vediamo come. Per iniziare, occorre creare un'istanza dell'oggetto Microsoft.XMLDOM. Come indica il nome, si tratta di un oggetto che consente di operare con file XML. Una volta creato l'oggetto, si imposta la proprietà Async su False: in tal modo lo script apprende che si desidera caricare il documento in modo sincrono anziché asincrono. Perché questa informazione è rilevante per lo script? A essere onesti, è probabile che per lui non lo sia: dopo tutto, gli script (come gli Scripting Guy) sono oggetti inanimati.

Tuttavia, per gli utenti lo è. Se si carica il documento in modo asincrono, infatti, l'esecuzione dello script continua anche quando il documento non è stato ancora caricato completamente. Questa operazione non è accettabile: è facile immaginare i problemi che si possono verificare quando si tenta di eseguire un'attività su un documento che non esiste ancora. Il caricamento sincrono di un file XML garantisce che il file sia completamente caricato prima che lo script proceda.

Per un'incredibile coincidenza, eccoci al punto in cui viene caricato il file XML. Per eseguire l'operazione, si richiama il metodo Load e si apre il file C:\Scripts\HARDWARE.xml, in cui è possibile visualizzare la seguente riga di codice:

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

In questo caso viene utilizzato il metodo selectNodes per eseguire una query sul file XML e comunicare allo script i nodi XML da recuperare. La sintassi, in effetti, è un po' insolita.

Innanzitutto, occorre specificare il percorso all'interno del file XML. Questo contiene un nodo di livello superiore denominato HARDWARE, seguito da una serie di nodi di secondo livello denominati COMPUTER. Ciascuno dei nodi rappresenta un singolo record all'interno del file di dati XML. Questa è la ragione per cui la query selectNodes inizia come segue:

//HARDWARE/COMPUTER

A questo punto, si incontra la seguente costruzione:

[@os='Windows XP']

È una porzione di query simile a una clausola WHERE in una query SQL standard. Con SQL, si può utilizzare una query di database simile a questa per ottenere un elenco di tutti i computer che utilizzano il sistema operativo Windows XP:

SELECT Name FROM Hardware 
    WHERE OS = 'Windows XP'

Con il metodo selectNodes, si esegue qualcosa di simile: si richiede di restituire un elenco di tutti i computer in cui l'attributo os (@os) è uguale a Windows XP. Per specificare che si tratta di una clausola WHERE, questa viene inserita per intero tra parentesi quadre.

Nota: questo tipo di query è noto come query XPath. Per ulteriori informazioni su XPath, consultare l'articolo all'indirizzo msdn.microsoft.com/library/ms256115.aspx.

Come già detto, è un po' strano, ma funziona. Se invece si volesse ottenere un elenco di tutti i computer che appartengono al reparto amministrativo? Semplice: il codice per il richiamo di selectNodes avrebbe il seguente aspetto:

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

Ancora una volta, la clausola WHERE è tra parentesi quadre, il nome dell'attributo (department) è preceduto dal simbolo chiocciola (@), quindi viene indicato il valore di interesse.

Facile, vero?

Dopo aver richiamato il metodo selectNodes, per visualizzare i nomi dei computer è sufficiente eseguire un loop nell'elenco dei valori restituiti e inserire un'istruzione Echo per la proprietà Text come illustrato di seguito:

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

Che tipo di informazioni si possono ottenere? A dire la verità, ci si aspetta esattamente di ottenere informazioni come queste:

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

In altre parole, vengono restituiti i nomi di tutti i computer che utilizzano ancora Windows XP.

A proposito, è possibile ottenere anche altro oltre al nome del computer: poiché si tratta del valore "predefinito" per ogni nodo, è semplicemente ciò che si ottiene facendo riferimento alla proprietà Text.

In alternativa, è possibile specificare esattamente i valori dell'attributo che si desidera ottenere. Come esempio si può esaminare il seguente loop For Each modificato:

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

Come si può notare, in questo loop viene ancora applicata la funzione Echo alla proprietà Text; tuttavia, è stata anche aggiunta la seguente riga di codice:

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

In questo caso si utilizza il metodo getNamedItem per recuperare il valore dell'attributo department, quindi si applica la funzione Echo alla proprietà Text per l'attributo. In tal modo è possibile specificare quali valori dell'attributo vengano visualizzati (e non) sulla schermata (si noti che è stato aggiunto il comando Wscript.Echo per inserire una riga vuota tra i record). Quando si esegue questo script, il risultato che si ottiene è il seguente:

atl-ws-001
Human Resources

atl-ws-002
Finance

atl-ws-007
Sales

atl-ws-009
Human Resources

Se necessario, si possono scrivere query più complesse. Ad esempio, si supponga che si desideri ottenere un elenco di tutti i computer che utilizzano Windows XP o Windows Vista. In SQL questa operazione si esegue scrivendo una query OR. Ebbene, la procedura per eseguire una query su un file XML è identica.

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

Ecco come si ottiene questo risultato: in un'unica serie di parentesi quadre sono stati forniti due criteri: @os='Windows XP' or @os='Windows Vista'. Con questo semplice comando, il risultato sarà simile a quello riportato nella Figura 3.

Figura 3 Risultato della query 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

Ricontrollando il file XML, si noterà che i computer che utilizzano Windows XP o Windows Vista sono elencati nell'output, mentre non lo sono quelli che utilizzano Windows Server 2003 o Windows Server 2008. Né dovrebbero esserlo.

Ci sono domande? Si deve scrivere una query più limitata, che restituisca solo i computer che utilizzano Windows XP e appartengono al reparto amministrativo? Come si può immaginare, è un'operazione semplice, infatti è sufficiente scrivere una query AND come la seguente:

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

Così facendo, verrà restituito il seguente set di dati:

atl-ws-002
Finance

Perché nel report è presente un unico elemento? Esatto: perché nel reparto amministrativo è presente un solo computer che utilizza Windows XP.

Speriamo di aver aiutato i lettori a occuparsi di questo specifico tipo di file XML. Se si dovesse scoprire l'esistenza di un ennesimo tipo di file XML, beh, buona fortuna.

Avendo iniziato l'articolo di questo mese con un famoso detto, ci sembra appropriato terminare con qualcosa di simile. Quindi vogliamo chiudere con le parole dell'imperatore Guglielmo II, che a noi Scripting Guy stanno molto a cuore: "Rinuncio per sempre al trono di Prussia e al trono imperiale tedesco a esso connesso".

Il rompicapo di script del Dottor Scripto

La sfida mensile che verifica non solo l'abilità nella risoluzione degli enigmi, ma anche le competenze di scripting.

Ottobre 2008: Cruciverba di VBScript

Per risolvere questo enigma, completare ciascuna riga con il nome di una funzione VBScript. Al termine, riordinare le lettere nelle caselle blu per scoprire il nome di un'ulteriore funzione.

fig10.gif

RISPOSTA:

Il rompicapo di script del Dottor Scripto

Risposta: Ottobre 2008: Cruciverba di VBScript

puzzle_answer.gif

Gli Scripting Guy, Greg Stemp e Jean Ross, lavorano per Microsoft.