Hey, Scripting Guy!Inseguire automobili... e XML

I Microsoft Scripting Guy

Scarica il codice per questo articolo: HeyScriptingGuy2007_02.exe (150KB)

"NON SO perché il mio cane insegue le automobili", recita una vecchia battuta. "Cosa se ne farebbe poi se ne raggiungesse una?"

Bella domanda, a cui gli Scripting Guy tra l'altro non sanno rispondere. A meno che a raggiungere l'auto non sia Lucy, il cane del quartiere. Siamo assolutamente certi che quel cane andrebbe a rapinare un'enoteca e poi userebbe l'auto per la fuga. E a giudicare dalle condizioni dei giardinetti qui davanti, siamo pronti a scommettere che non si fermerebbe ai servizi sulla strada, non so se ci siamo capiti...

Se dovessimo riportare la vecchia battuta all'attuale era informatica, potrebbe diventare così: "Non so perché il mio amministratore di sistema insiste a voler imparare XML. Cosa se ne farebbe poi se lo imparasse?"

Nota A nostra discolpa, avevamo detto solo che avremmo aggiornato la vecchia battuta, non che l'avremmo resa divertente.

Onestamente, forse XML è una tecnologia leggermente sopravvalutata, almeno per quanto riguarda la gestione dei sistemi. La verità è che molti amministratori di sistema hanno vissuto a lungo e felicemente senza mai scrivere un solo script che interagisse con un file XML e non prevediamo che le cose cambino da un momento all'altro.

Detto questo, è anche vero che sempre più applicazioni adottano XML come standard per l'archiviazione dei dati. E perché no? Dato che non sono altro che file di testo un po' arzigogolati, questi file di dati XML sono facili e veloci da creare, sono trasferibili da una piattaforma all'altra e non richiedono programmi di database complicati e costosi. Hai un sistema operativo e un editor di testo? Allora puoi creare un database XML.

Il che significa, naturalmente, che c'è almeno una cosa che un amministratore di sistema può fare con XML: scrivere script per inviare query a un file XML come se fosse un vero e proprio database. E allora, chi meglio degli Scripting Guy per offrire qualche suggerimento su come farlo?

Bene, bersaglio centrato. Se dovessimo provare a indovinare, scommetteremmo che in questo momento Lucy sia troppo impegnata a scavare nelle aiuole di qualche vicino per scrivere un articolo su XML.

Per cominciare, esaminiamo un semplice file XML (Figura 1), un file di database con quattro script pubblicati nella rubrica quotidiana Hey, Scripting Guy!.

Figure 1 Hey, Scripting Guy! Script in XML

<?xml version="1.0" encoding="ISO-8859-1"?>
<Repository>
  <Script>
    <Category>Microsoft Office</Category>
    <Subcategory>Microsoft Access</Subcategory>
    <Keyword>databases</Keyword>
    <Title>How Can I Print a Microsoft Access Report?</Title>
    <URL>https://www.microsoft.com/technet/scriptcenter/resources/qanda/oct06/hey1020.mspx</URL>
  </Script>
  <Script>
    <Category>Microsoft Office</Category>
    <Subcategory>Microsoft Access</Subcategory>
    <Keyword>databases</Keyword>
    <Title>How Can I Compact a Microsoft Access Database?</Title>
    <URL>https://www.microsoft.com/technet/scriptcenter/resources/qanda/oct06/hey1009.mspx</URL>
  </Script>
  <Script>
    <Category>Microsoft Office</Category>
    <Subcategory>Microsoft Word</Subcategory>
    <Keyword>hyperlinks</Keyword>
    <Title>How Can I Change an Existing Hyperlink in a Microsoft Word Document?</Title>
    <URL>https://www.microsoft.com/technet/scriptcenter/resources/qanda/oct06/hey1016.mspx</URL>
  </Script>
  <Script>
    <Category>Enterprise Servers</Category>
    <Subcategory>Microsoft SQL Server</Subcategory>
    <Keyword>databases</Keyword>
    <Title>How Can I Create a Table in a SQL Server Database?</Title>
    <URL>https://www.microsoft.com/technet/scriptcenter/resources/qanda/oct06/hey1016.mspx</URL>
  </Script>
</Repository>

Come si può vedere, è un piccolo file molto semplice. Ogni singolo script si trova sotto un tag <Script>. D'ora in avanti chiameremo questi script "record". Sì, è vero, gli esperti di XML non li chiamerebbero mai record. Ma non è un problema: il nostro scopo qui è mostrare come applicare una cosa che si conosce già, ossia le tecniche di query ai database, a un nuovo e diverso tipo di origine dati. Abbiamo pensato di concentrarci per prima cosa sull'aspetto pratico della questione per poi magari tornare sull'argomento in futuro e fornire la terminologia corretta.

Quindi, torniamo ai record. Ogni record contiene i seguenti campi: <Category> (categoria), <Subcategory> (sottocategoria), <Keyword> (parola chiave), <Title> (titolo) e <URL>.

Non vedo un grande entusiasmo tra il pubblico. Forse possiamo migliorare le cose mostrando uno script che consente di aprire questo file XML e restituire il contenuto:

Set xmlDoc = CreateObject("Microsoft.XMLDOM")
xmlDoc.Async = "False"
xmlDoc.Load("C:\Scripts\Scripts.xml")

Set colNodes = xmlDoc.selectNodes _
("/Repository/Script/*")

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

Nota Attenzione: questi nomi di tag distinguono tra maiuscole e minuscole. La versione corretta è "/Repository/Script", non "/repository/script" o "/REPOSITORY/SCRIPT".

D'accordo, nemmeno questo ha fatto una grande impressione. Ma è proprio questo il punto: non è assolutamente difficile come si potrebbe pensare.

Come si può vedere nel codice, per cominciare creiamo un'istanza dell'oggetto Microsoft.XMLDOM, l'oggetto COM utilizzato per lavorare con i file XML. Poi impostiamo la proprietà Async su False. In questo modo è possibile garantire che l'intero file venga letto in memoria prima di restituire il controllo allo script. Utilizziamo poi il metodo Load per leggere il file C:\Scripts\Scripts.xml:

xmlDoc.Load("C:\Scripts\Scripts.xml")

Appena il file è stato caricato in memoria, possiamo usare il metodo selectNodes per selezionare i record specificati dal database:

Set colNodes = xmlDoc.selectNodes _
("/Repository/Script/*")

Osserviamo attentamente il parametro inoltrato a selectNodes. In realtà, questo rappresenta il percorso all'interno del file XML. Il nostro file XML ha la seguente struttura:

<Repository>
    <Script>
        <Category></Category>
        <Subcategory></Subcategory>
        <Keyword></Keyword>
        <Title></Title>
        <URL></URL>
    </Script>
</Repository>

"È importante?" chiederete. In una parola, sì! Quando si lavora con i file XML, la struttura è molto importante. Ad esempio, come possiamo ricavare le singole proprietà di un record? È facile: Accediamo al tag <Repository> seguito dal tag <Script> seguito dai tag delle singole proprietà. E guarda un po'. Questo è lo stesso percorso specificato come parametro per selectNodes. Facciamo semplicemente seguire questo percorso da /*, che significa "Seleziona tutte le proprietà per questi record". In altre parole, l'insieme restituito sarà composto da tutte le proprietà di tutti i record del database, come una query "Select * From" in Strumentazione gestione Windows® (WMI).

Nota Prova a usare lo script di esempio e vedrai esattamente cosa intendiamo.

Il resto dello script è facile: ci limitiamo a impostare un ciclo For Each per scorrere tutto l'insieme e restituire il valore della proprietà Text per ogni elemento e ogni proprietà:

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

Molto più facile che inseguire le automobili.

Ma hai ragione: se avessimo voluto semplicemente restituire l'intero contenuto del file, avremmo potuto lasciar perdere XML e usare semplicemente FileSystemObject. Avrebbe potuto essere un filino più complicato, ma solo un filino. Se la nostra intenzione era meravigliare e far pensare "Ehi, dopotutto questo XML è veramente utile", allora probabilmente abbiamo ancora parecchia strada da fare.

E allora vediamo di rimediare. Nel primo script abbiamo ottenuto i valori delle proprietà per tutti i record. Va bene, ma se quello che ci interessava ottenere fosse stato semplicemente il titolo dello script? Lo possiamo fare? Un attimo solo...

Va bene, secondo Lucy basta modificare il comando selectNodes aggiungendo la proprietà che ci interessa alla fine del percorso. In altre parole:

    Set colNodes=xmlDoc.selectNodes _    ("/Repository/Script/Title")

L'unico motivo per cui la prima volta abbiamo ottenuto tutte le proprietà è che abbiamo usato il carattere jolly *. Ora otteniamo solo la proprietà Title. Perché? Perché è l'unico valore della proprietà che abbiamo chiesto.

Nota Guarda un po': XML ti dà esattamente quello che chiedi. Senza offesa, Lucy, ma crediamo che XML sia il nuovo migliore amico dell'uomo!

E naturalmente si può ottenere più di una proprietà. Ad esempio, questo comando modificato restituisce i valori per le proprietà Title e URL:

    Set colNodes=xmlDoc.selectNodes _    ("/Repository/Script/(Title | URL)")

È vero che la sintassi non è semplicissima, ma una volta abituati non è poi così difficile. Per cominciare, specifichiamo la parte principale del percorso, proprio come abbiamo fatto prima:

    /Repository/Script/

Aggiungiamo poi delle parentesi e al loro interno specifichiamo le proprietà da restituire. Si noti che usiamo la barra verticale, ossia il carattere |, come separatore tra le singole proprietà. In altre parole:

    (Title | URL)

Come abbiamo già detto, magari non è bellissimo, ma funziona.

Ed è possibile anche ottenere più di due proprietà. Basta continuare ad aggiungere barre verticali per ottenere tutte le informazioni desiderate. Ad esempio, il seguente comando restituisce tre proprietà (Title, URL e Keyword):

    Set colNodes=xmlDoc.selectNodes _    ("/Repository/Script/(Title | URL |          Keyword)")

Interessante, no?

Beh, a noi sembra interessante. Sei proprio incontentabile. Ma di nuovo non hai tutti i torti: finora abbiamo semplicemente recuperato informazioni su tutti i record del database. Non che ci sia niente di male in questo. Spesso è esattamente ciò che serve. Però ci saranno anche dei casi (molti casi) in cui si vogliono recuperare informazioni relative solo a un sottoinsieme di quei record. Ad esempio, si potrebbero voler ottenere solo le informazioni relative agli script la cui Keyword (parola chiave) è uguale a databases. Allora si potrebbe usare una query come questa:

    Set colNodes=xmlDoc.selectNodes _
    ("/Repository/Script " & _
    "[Keyword = ‘databases’]")

Di nuovo, la sintassi è un po' strana. D'altra parte, però, è anche semplice e lineare. Dopo avere specificato il percorso principale, inseriamo la clausola "Where" (ad esempio, dove x è uguale a y) tra parentesi quadre, in questo modo:

/Repository/Script [Keyword = ‘databases’]

Come probabilmente avrai già capito, il nostro equivalente della clausola Where indica allo script di restituire solo gli elementi in cui l'attributo Keyword è uguale a databases. Si noti che databases è racchiuso tra virgolette singole. Non solo va bene così, ma è praticamente necessario. Se il termine filtro è racchiuso tra virgolette doppie, si verifica un errore di sintassi quando si cerca di eseguire lo script.

Nota Perché? Perché, ricordiamo, l'intera stringa di query "/Repository/Script [Keyword = 'databases']" è racchiusa tra virgolette doppie.

Naturalmente non si può usare solo il segno di uguale (=) per filtrare i dati. Si possono usare i segni maggiore di (>) o minore di (<), oltre ai noti segni di maggiore o uguale (<=) e minore o uguale (>=). Si può anche negare uno qualsiasi di questi segni facendolo precedere da un punto esclamativo. Ad esempio, questo comando richiede tutti gli script in cui la Keyword non è uguale a databases (notare il segno !=).

    Set colNodes=xmlDoc.selectNodes _
    ("/Repository/Script " & _
    "[Keyword != ‘databases’]")

Un attimo: chi ha detto "Va bene, si può impostare un filtro, ma scommetto che non si può impostare un filtro e specificare le proprietà che devono essere restituite"? Certo che si può:

    Set colNodes=xmlDoc.selectNodes _
    ("/Repository/Script " & _
    "[Keyword = ‘databases’]/Title")

Se tutto va bene, questo comando restituirà solo la proprietà Title per tutti gli script in cui la Keyword è uguale a databases. Vediamo se funziona:

    How Can I Print a Microsoft Access Report?
    How Can I Compact a Microsoft Access Database?
    How Can I Create a Table in a SQL Server     Database?

Vediamo se possiamo infilarci un altro comando prima di chiudere. Anche se stiamo facendo progressi, forse stiamo ancora ottenendo più record di quelli che effettivamente vogliamo. Dopotutto il comando precedente restituisce un insieme di script Microsoft® Access® e di script Microsoft SQL Server™. Perché? Perché in tutti questi script la Keyword è uguale a 'databases'. E se volessimo limitare i dati restituiti agli script in cui la Keyword è uguale a 'databases' e la Subcategory è uguale a 'Microsoft SQL Server'? È possibile filtrare per criteri multipli?

Ma c'era bisogno di chiederlo?

    Set colNodes=xmlDoc.selectNodes _
    ("/Repository/Script " & _
    "[Keyword = ‘databases’ and " & _
    "Subcategory = ‘Microsoft SQL Server’]")

È la stessa sintassi di base. Abbiamo semplicemente utilizzato due criteri separati (ossia Keyword = 'databases' e Subcategory = 'Microsoft SQL Server') collegandoli con l'operatore AND.

Nota Sì, è vero: con questo semplice e piccolo file XML avremmo potuto semplicemente richiedere tutti gli script in cui la Subcategory è uguale a 'Microsoft SQL Server'. Ma sarebbe stato poco interessante e molto meno istruttivo.

Si possono utilizzare anche clausole OR. Ad esempio, poniamo di avere una quantità di script di Microsoft Office, tra cui script con Subcategory uguale a Microsoft Excel®, Microsoft PowerPoint®, Microsoft Outlook® e così via. È possibile limitare i dati restituiti solo agli script delle sottocategorie Microsoft Word o Microsoft Access? Ma certo:

    Set colNodes=xmlDoc.selectNodes _
    ("/Repository/Script " & _
    "[Subcategory = ‘Microsoft Word’ " & _
    "or Subcategory = ‘Microsoft Access’]")

Meglio così? D'accordo, questo non sarà uno di quegli articoli che ti cambierà la vita, però ci sono buone probabilità che prima o poi risulterà utile poter inviare una query a un file XML in questo modo. Ma sta a te scegliere: puoi imparare alcune tecniche di base per XML o inseguire le automobili. Dipende da te. Se scegli le automobili e ti capita di incontrare Lucy, il cane del quartiere, salutala da parte degli Scripting Guy. E dille di starsene fuori dal nostro giardino!

Hey, Scripting Guy! - Ogni giorno

Hai appena letto l'articolo Hey, Scripting Guy! di questo mese e pensato che fosse il miglior pezzo tecnico mai letto. Potresti addirittura arrivare a dire che è il miglior pezzo mai scritto in assoluto. Non solo, ma stai tenendo d'occhio con impazienza la posta in attesa del prossimo numero di TechNet Magazine solo per poter leggere un altro articolo come questo.

Che cosa stai aspettando? Vuoi saperne di più su Lucy, il cane del vicinato, o leggere le ultime imprese dello Scripting Son? Sai come è andato il campionato annuale di Turducken l'anno scorso? Tieniti aggiornato su questi importanti argomenti leggendo gli articoli quotidiani (ebbene sì, abbiamo detto quotidiani), di Hey, Scripting Guy!. Ogni giorno dal lunedì al venerdì (tranne i festivi e i giorni in cui gli Scripting Guy sono in vacanza), puoi leggere le ultime notizie sul baseball giocato nelle scuole, il football e il basket giocati nelle università e ogni tanto anche le previsioni del tempo locali. D'accordo, sono locali solo per chi abita a Redmond, ma chi non vuole sapere com'è il tempo a Redmond?

Non solo, ma imparerai anche qualcosa di nuovo sugli script ogni giorno. Sì, nascoste tra queste storie avvincenti ci sono anche informazioni sugli script. In ogni articolo, gli Scripting Guy rispondono a domande reali inviate da lettori che si ritengono essere reali. Puoi leggere l'articolo quotidiano in linea all'indirizzo microsoft.com/technet/scriptcenter/resources/qanda. Inoltre, poiché hanno già risposto a centinaia di domande, gli archivi sono piuttosto corposi e quindi rappresentano un'ottima fonte di informazioni sugli script (vedi micros­oft.com/technet/scriptcenter/resources/qanda/hsgarch.mspx).

Hai una domanda per gli Scripting Guy? C'è una remota possibilità di ottenere una risposta inviando la domanda all'indirizzo scripter@microsoft.com. Se invece non la invii non esiste nemmeno questa remota possibilità, quindi non hai niente da perdere. A differenza di un biglietto della lotteria, è gratis e le probabilità sono leggermente maggiori.

I Microsoft Scripting Guy lavorano o, per meglio dire, sono stipendiati da Microsoft. Quando non si dedicano al baseball (o vaie altre attività) da giocatori, allenatori o semplici spettatori gestiscono il TechNet Script Center. Consultalo alla pagina www.scriptingguys.com.

© 2008 Microsoft Corporation e CMP Media, LLC. Tutti i diritti riservati. È vietata la riproduzione completa o parziale senza autorizzazione.