HOWTO · PowerShell

PowerShell을 사용하여 XML 파일을 구문 분석하는 방법

이 기사는 Windows PowerShell을 사용하여 XML 파일을 적절하게 파싱하는 방법에 대해 논의할 것입니다.

이 페이지의 내용

PowerShell에서 XML 값을 추출하려면 빠른 조회에는 XPath 식과 함께 Select-Xml을 사용하고, 불러온 문서를 탐색해야 할 때는 System.Xml.XmlDocument를, XML을 스트림으로 순차적으로 읽을 때는 System.Xml.XmlTextReader를 사용합니다. 아래 예제는 XML을 읽기만 합니다. 작은 컴퓨터 목록을 사용해 요소의 텍스트와 특성 값이 어떻게 다른지 보여 줍니다.

Select-Xml으로 XML 요소와 특성 파싱하기

Select-Xml은 XPath 식을 평가해 일치하는 개체를 반환합니다. 각 일치 항목의 Node 속성에서 선택된 XML 노드에 접근할 수 있습니다. 요소의 텍스트를 읽으려면 InnerText를 사용합니다. InnerXml은 요소 안에 포함된 마크업을 반환하므로, 내부 콘텐츠 자체를 XML로 다뤄야 할 때 유용합니다.

다음 예제를 실행합니다.

이 섹션의 코드와 표시되는 레이블 또는 출력은 영어로 유지됩니다.

$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

XPath /Computers/Computer/Name은 루트부터 각 Name 요소까지의 계층을 따라갑니다. 특성을 선택하려면 Computer 요소를 선택한 다음 일치한 각 노드에서 name 특성을 읽습니다. XML의 구조에 맞게 XPath를 변경하세요. 요소 이름과 대소문자는 문서와 일치해야 합니다. 데이터가 이미 문자열에 있다면 Select-Xml의 -Content 매개 변수에 XML 내용을 전달할 수도 있습니다. 예제 출력에는 추출된 컴퓨터 이름과 특성 값이 표시됩니다. 출력에 있는 그룹 레이블은 코드와의 바이트 일치를 위해 영어로 유지됩니다.

System.Xml.XmlDocument로 XML 불러오고 조회하기

System.Xml.XmlDocument는 문서를 탐색할 수 있는 트리 구조로 불러옵니다. 여러 관련 조회를 수행하거나 부모 노드와 자식 노드 사이를 이동해야 하는 스크립트에 편리합니다. 다만 문서 전체를 메모리에 보관하므로, 매우 큰 파일에는 스트리밍 리더가 더 적합할 수 있습니다.

이 예제는 임시 XML 파일을 불러와 각 컴퓨터를 선택하고, Name 자식 요소가 있는지 확인한 뒤 값을 읽습니다. XML 스키마상 해당 요소가 없을 수 있다면 이 확인 과정이 중요합니다. 일치하는 노드가 없으면 SelectSingleNode()는 $null을 반환합니다.

이 섹션의 코드와 표시되는 레이블 또는 출력은 영어로 유지됩니다.

$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

요소 안의 마크업이 아니라 텍스트 값을 읽으려면 InnerXml 대신 InnerText를 사용하세요. 문서에 기본 XML 네임스페이스가 있으면 접두사 없는 XPath 식이 요소와 일치하지 않을 수 있습니다. 이 경우 XmlNamespaceManager를 만들고 조회 식에서 접두사를 사용하세요.

System.Xml.XmlTextReader로 XML을 스트림으로 읽기

System.Xml.XmlTextReader는 정방향으로만 이동하는 읽기 전용 리더를 통해 XML 노드를 문서 순서대로 제공합니다. 전체 문서 트리를 만들지 않으므로 큰 입력에서 메모리 사용량을 줄일 수 있습니다. 뒤로 이동할 수 없기 때문에 관련 노드가 지나갈 때 각 값을 추출해야 합니다. 처리가 일찍 중단되더라도 파일 핸들이 해제되도록 finally 블록에서 리더를 닫으세요.

다음 예제는 각 Computer 시작 요소에서 name 특성을 읽습니다. 예제에서 XML 파일을 직접 만들고 처리 후 리더를 해제합니다.

이 섹션의 코드와 표시되는 레이블 또는 출력은 영어로 유지됩니다.

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

특성 대신 요소의 텍스트를 읽으려면 일치하는 요소 이름인지 확인하고, 리더가 해당 요소에 위치했을 때 텍스트를 읽으세요. ReadString()은 텍스트 내용을 읽은 뒤 리더를 다음 위치로 이동하므로, 더 복잡한 루프에서는 이 이동을 고려해야 합니다. 사용이 끝나면 리더를 해제하세요. 리더를 열어 둔 채로 두면 입력 파일이 잠긴 상태로 남을 수 있습니다.

PowerShell XML 파싱 방법 선택하기

파일이나 문자열에서 몇 개의 노드만 가져오며 짧은 XPath 조회가 가장 명확하다면 Select-Xml을 선택하세요. 편리한 트리 탐색, 여러 조회 또는 관련 노드 접근이 필요하면 System.Xml.XmlDocument를 사용하세요. 노드를 순서대로 처리할 수 있고 전체 트리를 메모리에 불러오지 않으려면 System.Xml.XmlTextReader를 선택하세요.

세 방법 모두 요소와 특성을 읽을 수 있습니다. 주된 차이는 문서를 제공하는 방식입니다. Select-Xml은 XPath 조회 결과를 반환하고, XmlDocument는 불러온 트리의 여러 위치를 탐색할 수 있으며, XmlTextReader는 스트림을 따라 앞으로 이동합니다. 문서 크기와 조회 방식에 맞는 방법을 고른 다음, 입력에 없을 수 있는 선택적 노드나 특성이 있는지 확인하세요.