HOWTO · PowerShell

Wie man XML-Dateien mit PowerShell analysiert

Dieser Artikel wird erörtern, wie wir XML-Dateien ordnungsgemäß mit Windows PowerShell analysieren können.

Auf dieser Seite

Um Werte aus XML in PowerShell auszulesen, verwenden Sie Select-Xml mit einem XPath-Ausdruck für eine schnelle Abfrage, System.Xml.XmlDocument, wenn Sie ein geladenes Dokument durchsuchen müssen, oder System.Xml.XmlTextReader, um es vorwärts als Stream zu lesen. Die folgenden Beispiele lesen XML ausschließlich aus. Sie verwenden ein kleines Computerinventar und zeigen den Unterschied zwischen Elementtext und Attributwerten.

XML-Elemente und -Attribute mit Select-Xml auslesen

Select-Xml wertet einen XPath-Ausdruck aus und gibt Trefferobjekte zurück. Jedes Trefferobjekt stellt den ausgewählten XML-Knoten über seine Eigenschaft Node bereit. Mit InnerText lesen Sie den Text eines Elements aus. InnerXml gibt dagegen das im Element enthaltene Markup zurück und ist nützlich, wenn Sie diesen Inhalt selbst als XML benötigen.

Führen Sie dieses Beispiel aus:

$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

Der XPath-Ausdruck /Computers/Computer/Name folgt der Hierarchie vom Stammelement bis zu jedem Name-Element. Für die Attributauswahl wählen Sie die Computer-Elemente aus und lesen das Attribut name aus jedem Trefferknoten aus. Die Ausgabebezeichnungen „Element names“ und „Attribute names“ bleiben im Beispiel auf Englisch: Unter „Element names“ stehen die Textwerte der Elemente, unter „Attribute names“ die Werte der jeweiligen name-Attribute. Passen Sie den XPath-Ausdruck an die Struktur Ihres XML-Dokuments an; Elementnamen und Groß-/Kleinschreibung müssen mit dem Dokument übereinstimmen. Select-Xml kann XML-Inhalt auch über den Parameter -Content entgegennehmen, wenn die Daten bereits als Zeichenfolge vorliegen.

XML mit System.Xml.XmlDocument laden und abfragen

System.Xml.XmlDocument lädt das Dokument in einen durchsuchbaren Baum. Das ist praktisch, wenn ein Skript mehrere zusammengehörige Abfragen ausführen oder zwischen übergeordneten und untergeordneten Knoten wechseln muss. Dabei wird das gesamte Dokument im Arbeitsspeicher gehalten; bei sehr großen Dateien kann daher ein Streaming-Reader besser geeignet sein.

Dieses Beispiel lädt eine temporäre XML-Datei, wählt jeden Computer aus und prüft vor dem Auslesen, ob ein untergeordnetes Name-Element vorhanden ist. Diese Prüfung ist wichtig, wenn das XML-Schema dieses Element nicht zwingend vorschreibt: SelectSingleNode() gibt bei fehlendem Treffer $null zurück.

$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

Verwenden Sie für den Textwert InnerText statt InnerXml, das eventuell im Element verschachteltes Markup zurückgibt. Hat das Dokument einen Standard-XML-Namespace, finden XPath-Ausdrücke ohne Präfix die Elemente möglicherweise nicht. Erstellen Sie in diesem Fall einen XmlNamespaceManager und verwenden Sie in der Abfrage ein Präfix.

XML mit System.Xml.XmlTextReader als Stream lesen

System.Xml.XmlTextReader stellt XML-Knoten mit einem ausschließlich vorwärts lesbaren und schreibgeschützten Reader in Dokumentreihenfolge bereit. Dabei wird kein vollständiger Dokumentbaum aufgebaut, was bei großen Eingaben den Speicherbedarf verringern kann. Da der Reader nicht rückwärts navigieren kann, lesen Sie jeden Wert aus, sobald der betreffende Knoten erreicht wird. Schließen Sie den Reader in einem finally-Block, damit der Dateihandle auch freigegeben wird, wenn die Verarbeitung vorzeitig endet.

Das folgende Beispiel liest das Attribut name aus jedem öffnenden Computer-Element. Es erstellt eine eigene XML-Datei und gibt den Reader nach der Verarbeitung frei.

$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
}

Wenn Sie statt eines Attributs den Elementtext auslesen möchten, prüfen Sie auf den passenden Elementnamen und lesen den Text aus, während der Reader auf diesem Element steht. ReadString() liest den Textinhalt und bewegt den Reader weiter; berücksichtigen Sie diese Bewegung daher in einer komplexeren Schleife. Geben Sie den Reader nach der Verwendung frei, denn ein noch geöffneter Reader kann die Eingabedatei sperren.

Eine PowerShell-Methode zum Parsen von XML auswählen

Verwenden Sie Select-Xml, wenn eine kurze XPath-Abfrage der klarste Weg ist, um einige Knoten aus einer Datei oder Zeichenfolge abzurufen. Wählen Sie System.Xml.XmlDocument, wenn Sie eine bequeme Navigation im Baum, mehrere Abfragen oder Zugriff auf zusammengehörige Knoten benötigen. System.Xml.XmlTextReader eignet sich, wenn Sie Knoten der Reihe nach verarbeiten können und vermeiden möchten, den gesamten Baum in den Arbeitsspeicher zu laden.

Alle drei Ansätze können Elemente und Attribute auslesen. Sie unterscheiden sich vor allem darin, wie sie das Dokument bereitstellen: Select-Xml gibt XPath-Treffer zurück, XmlDocument ermöglicht die Navigation in einem geladenen Baum und XmlTextReader bewegt sich vorwärts durch einen Stream. Wählen Sie den Ansatz passend zur Dokumentgröße und zum Abfragemuster. Prüfen Sie außerdem auf optionale Knoten oder Attribute, wenn die Eingabe diese auslassen kann.