Reading XML via PowerShell

CodeMaester

Assume I have this XML file:

<?xml version="1.0" encoding="UTF-8"?>
<books>
  <book id="book1">
    <chapters>
      <chapter1>Begin</chapter1>
      <chapter2>mid</chapter2>
      <chapter3>end</chapter3>
    </chapters>
    <pages>352</pages>
  </book>
  <book id="book2">
    <chapters>
      <chapter1>woop</chapter1>
      <chapter2>doop</chapter2>
      <chapter3>goop</chapter3>
    </chapters>
    <pages>761</pages>
  </book>
</books>

Now I want to read this with PowerShell, e.g.:

$file = "C:\path\books.xml"
$xml = [xml](Get-Content $file)

$books = $xml.books.book.id

foreach ($book in $books) {
    ...
}

In the loop I want to get the chapters of each book, so I tried this:

$xml.books.book | ? {$_.id -eq $book} | select chapters.chapter1

but that didn't work. So I tried this instead:

(xml.books.book | where $_.id -eq $book).chapters.chapter1

Both won't work for some reason. How can I get these values?

Ansgar Wiechers

Your first approach didn't work, because Select-Object lets you select properties (chapters), but not nested properties (chapters.chapter1). You'd need to expand the properties and cascade the cmdlet calls to get the child property values:

$xml.books.book |
    Where-Object {$_.id -eq $book} |
    Select-Object -Expand chapters |
    Select-Object -Expand chapter1

Your second approach didn't work, because you omitted the $ from $xml and you didn't get the abbreviated Where-Object syntax right. If you want to use short Where-Object filter notation it's <cmdlet> <property> <op> <value> without the current object variable ($_):

($xml.books.book | Where-Object id -eq $book).chapters.chapter1

otherwise you need the regular syntax:

($xml.books.book | Where-Object {$_.id -eq $book}).chapters.chapter1

With that said, none of the approaches is very elegant. For your example scenario you could simply use dot-notation to get all <chapter1> values:

$xml.books.book.chapters.chapter1

If you need more control it's usually more efficient to use XPath expressions, though, e.g. if you want a list of all book IDs:

$xml.SelectNodes('//book/@id') | Select-Object -Expand '#text'

or if you want to select the third chapter of the book with the ID "book2":

$id = 'book2'
$xml.SelectSingleNode("//book[@id='$id']/chapters/chapter3").'#text'

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related