HOWTO · PowerShell
Come analizzare file XML utilizzando PowerShell
Questo articolo discuterà di come possiamo analizzare i file XML correttamente utilizzando Windows PowerShell.
In questa pagina
Per estrarre valori da XML in PowerShell, usa Select-Xml con un’espressione XPath per una query rapida, System.Xml.XmlDocument per navigare in un documento caricato oppure System.Xml.XmlTextReader per leggerlo in avanti come flusso. Gli esempi seguenti leggono soltanto XML. Usano un piccolo inventario di computer e mostrano la differenza tra il testo di un elemento e i valori dei suoi attributi.
Analizzare elementi e attributi XML con Select-Xml
Select-Xml valuta un’espressione XPath e restituisce oggetti corrispondenti. Ogni risultato espone il nodo XML selezionato tramite la proprietà Node. Usa InnerText per leggere il testo di un elemento; InnerXml restituisce il markup contenuto nell’elemento, utile quando serve proprio quel contenuto come XML.
Esegui questo esempio:
$path = Join-Path ([System.IO.Path]::GetTempPath()) "computers-$([guid]::NewGuid()).xml"
@'
<Computers>
<Computer name="WINPC-01" ip="127.0.0.1"><Name>WINPC-01</Name></Computer>
<Computer name="WINPC-02" ip="192.168.1.105"><Name>WINPC-02</Name></Computer>
</Computers>
'@ | Set-Content -Path $path -Encoding utf8
Write-Output 'Element names:'
Select-Xml -Path $path -XPath '/Computers/Computer/Name' |
ForEach-Object { $_.Node.InnerText }
Write-Output 'Attribute names:'
Select-Xml -Path $path -XPath '/Computers/Computer' |
ForEach-Object { $_.Node.GetAttribute('name') }
Remove-Item -Path $path
Element names:
WINPC-01
WINPC-02
Attribute names:
WINPC-01
WINPC-02
Nell’output, il gruppo con l’etichetta inglese “Element names” mostra il testo degli elementi, mentre quello con l’etichetta inglese “Attribute names” mostra i valori dell’attributo name. Le etichette restano in inglese.
Il percorso XPath /Computers/Computer/Name segue la gerarchia dalla radice fino a ciascun elemento Name. Per selezionare gli attributi, seleziona gli elementi Computer e leggi l’attributo name dal nodo di ogni risultato. Modifica il percorso XPath in base alla struttura del tuo XML: i nomi degli elementi e le maiuscole devono corrispondere a quelli del documento. Se i dati sono già in una stringa, Select-Xml accetta anche il contenuto XML tramite il parametro -Content.
Caricare e interrogare XML con System.Xml.XmlDocument
System.Xml.XmlDocument carica il documento in un albero navigabile. È comodo quando uno script deve eseguire più query correlate o spostarsi tra nodi padre e figlio. Il documento, però, viene mantenuto in memoria: per file molto grandi può essere più adatto un lettore in streaming.
Questo esempio carica un file XML temporaneo, seleziona ogni computer e verifica la presenza di un elemento figlio Name prima di leggerlo. Il controllo è utile se lo schema XML consente che tale elemento sia assente: SelectSingleNode() restituisce $null quando non trova corrispondenze.
$path = Join-Path ([System.IO.Path]::GetTempPath()) "computers-$([guid]::NewGuid()).xml"
@'
<Computers>
<Computer><Name>WINPC-01</Name></Computer>
<Computer><Ip>192.168.1.105</Ip></Computer>
</Computers>
'@ | Set-Content -Path $path -Encoding utf8
$document = [System.Xml.XmlDocument]::new()
$document.Load($path)
foreach ($computer in $document.SelectNodes('/Computers/Computer')) {
$nameNode = $computer.SelectSingleNode('Name')
if ($null -ne $nameNode) {
Write-Output $nameNode.InnerText
}
else {
Write-Output 'No Name element'
}
}
Remove-Item -Path $path
Per ottenere il valore testuale, usa InnerText invece di InnerXml, che restituisce l’eventuale markup annidato nell’elemento. Se il documento ha uno spazio dei nomi XML predefinito, le espressioni XPath senza prefisso potrebbero non trovare gli elementi; crea un XmlNamespaceManager e usa un prefisso nella query.
Leggere XML come flusso con System.Xml.XmlTextReader
System.Xml.XmlTextReader espone i nodi XML nell’ordine del documento tramite un lettore di sola lettura che procede in avanti. Evita di costruire l’intero albero del documento e può quindi ridurre l’uso di memoria con input di grandi dimensioni. Poiché non consente di tornare ai nodi precedenti, estrai ciascun valore quando il lettore raggiunge il nodo corrispondente. Chiudilo in un blocco finally per rilasciare il file anche se l’elaborazione si interrompe in anticipo.
L’esempio seguente legge l’attributo name da ogni elemento di apertura Computer. Crea un proprio file XML e rilascia il lettore al termine dell’elaborazione.
$path = Join-Path ([System.IO.Path]::GetTempPath()) "computers-$([guid]::NewGuid()).xml"
@'
<Computers>
<Computer name="WINPC-01" ip="127.0.0.1" />
<Computer name="WINPC-02" ip="192.168.1.105" />
</Computers>
'@ | Set-Content -Path $path -Encoding utf8
$reader = [System.Xml.XmlTextReader]::new($path)
try {
while ($reader.Read()) {
if ($reader.NodeType -eq [System.Xml.XmlNodeType]::Element -and
$reader.Name -eq 'Computer') {
Write-Output $reader.GetAttribute('name')
}
}
}
finally {
$reader.Dispose()
Remove-Item -Path $path
}
Per leggere il testo di un elemento invece di un attributo, verifica il nome dell’elemento corrispondente e leggi il testo quando il lettore si trova su quel nodo. ReadString() legge il contenuto testuale e fa avanzare il lettore: nei cicli più complessi, tieni conto di questo spostamento. Al termine, rilascia il lettore; se resta aperto, il file di input potrebbe rimanere bloccato.
Scegliere un metodo di analisi XML in PowerShell
Scegli Select-Xml quando una breve query XPath è il modo più chiaro per recuperare alcuni nodi da un file o da una stringa. Scegli System.Xml.XmlDocument se ti servono una navigazione comoda nell’albero, più query o l’accesso a nodi correlati. Scegli System.Xml.XmlTextReader quando puoi elaborare i nodi in sequenza e vuoi evitare di caricare in memoria l’intero albero.
Tutti e tre gli approcci possono leggere elementi e attributi. Cambia il modo in cui espongono il documento: Select-Xml restituisce le corrispondenze XPath, XmlDocument consente di navigare nell’albero caricato e XmlTextReader procede in avanti attraverso un flusso. Scegli l’approccio adatto alle dimensioni del documento e al tipo di query, quindi verifica la presenza di nodi o attributi facoltativi quando l’input potrebbe non includerli.