HOWTO · PowerShell

Como Analisar Arquivos XML Usando PowerShell

Este artigo discutirá como podemos analisar arquivos XML corretamente usando o Windows PowerShell.

Nesta página

Para extrair valores de XML no PowerShell, use Select-Xml com uma expressão XPath para uma consulta rápida, System.Xml.XmlDocument quando precisar navegar por um documento carregado ou System.Xml.XmlTextReader para lê-lo sequencialmente como um fluxo. Os exemplos abaixo apenas leem XML. Eles usam um pequeno inventário de computadores e mostram a diferença entre o texto de um elemento e os valores de atributos.

Analisar elementos e atributos XML com Select-Xml

Select-Xml avalia uma expressão XPath e retorna objetos correspondentes. Cada correspondência expõe o nó XML selecionado por meio da propriedade Node. Use InnerText para ler o texto de um elemento; InnerXml retorna a marcação contida nele, o que é útil quando esse conteúdo também precisa ser tratado como XML.

Execute este exemplo:

$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

No resultado, o grupo identificado pelo rótulo em inglês “Element names” mostra o texto dos elementos Name; o grupo “Attribute names” mostra os valores do atributo name. Os dois rótulos permanecem em inglês.

Element names:
WINPC-01
WINPC-02
Attribute names:
WINPC-01
WINPC-02

O XPath /Computers/Computer/Name percorre a hierarquia da raiz até cada elemento Name. Para selecionar atributos, selecione os elementos Computer e leia o atributo name de cada nó correspondente. Altere o XPath para corresponder à estrutura do seu XML; os nomes dos elementos e o uso de maiúsculas e minúsculas devem coincidir com o documento. Select-Xml também aceita conteúdo XML pelo parâmetro -Content quando os dados já estão em uma string.

Carregar e consultar XML com System.Xml.XmlDocument

System.Xml.XmlDocument carrega o documento em uma árvore navegável. Isso é conveniente quando um script precisa fazer várias consultas relacionadas ou passar entre nós pais e filhos. A contrapartida é que o documento fica na memória; por isso, um leitor de fluxo pode ser mais adequado para arquivos muito grandes.

Este exemplo carrega um arquivo XML temporário, seleciona cada computador e verifica se há um elemento filho Name antes de lê-lo. Essa verificação é importante quando o esquema XML permite que o elemento esteja ausente: SelectSingleNode() retorna $null quando não há correspondência.

$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

Use InnerText para obter o valor textual, em vez de InnerXml, que retorna qualquer marcação aninhada no elemento. Se o documento tiver um namespace XML padrão, expressões XPath sem prefixo podem não encontrar seus elementos; crie um XmlNamespaceManager e use um prefixo na consulta.

Ler XML como um fluxo com System.Xml.XmlTextReader

System.Xml.XmlTextReader expõe os nós XML na ordem do documento por meio de um leitor somente de leitura e que avança apenas para a frente. Ele evita construir uma árvore completa do documento, o que pode reduzir o uso de memória com entradas grandes. Como não é possível voltar na leitura, extraia cada valor quando o nó correspondente aparecer. Feche o leitor em um bloco finally para liberar o identificador do arquivo mesmo que o processamento seja interrompido antes do fim.

O exemplo a seguir lê o atributo name de cada elemento inicial Computer. Ele cria seu próprio arquivo XML e descarta o leitor após o processamento.

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

Para ler o texto de um elemento em vez de um atributo, verifique se o nome do elemento corresponde e leia seu texto enquanto o leitor estiver posicionado nele. ReadString() lê o conteúdo textual e avança o leitor; portanto, leve esse movimento em conta em um loop mais complexo. Descarte o leitor ao terminar; se ele permanecer aberto, o arquivo de entrada poderá continuar bloqueado.

Escolher um método de análise de XML no PowerShell

Escolha Select-Xml quando uma consulta XPath curta for a maneira mais clara de obter alguns nós de um arquivo ou de uma string. Escolha System.Xml.XmlDocument quando precisar de navegação prática pela árvore, de várias consultas ou de acesso a nós relacionados. Escolha System.Xml.XmlTextReader quando puder processar os nós em ordem e quiser evitar carregar uma árvore inteira na memória.

As três abordagens podem ler elementos e atributos. A principal diferença está na forma como expõem o documento: Select-Xml retorna correspondências XPath, XmlDocument permite navegar por uma árvore carregada e XmlTextReader avança por um fluxo. Escolha a abordagem que se adapte ao tamanho do documento e ao padrão das consultas; em seguida, verifique se há nós ou atributos opcionais quando a entrada puder omiti-los.