DukeDonnovan
DukeDonnovan

Reputation: 140

How-To select elements from my XML-file in powershell

I want to control the execution of a PowerShell programm by an XML-file. I started to design the XML-file and it currently looks like this:

<?xml version="1.0" encoding="utf-8"?>
<Sequences>
  <Sequence>
    <SequenceName>Sequence-A</SequenceName>
    <SequenceNumber>01</SequenceNumber>
    <Package>
      <PackageFolder>Package-A</PackageFolder>
      <PackageNumber>01</PackageNumber>
    </Package>
    <Package>
      <PackageFolder>Package-B</PackageFolder>
      <PackageNumber>02</PackageNumber>
    </Package>
  </Sequence>
  <Sequence>
    <SequenceName>Sequence-B</SequenceName>
    <SequenceNumber>02</SequenceNumber>
    <Package>
      <PackageFolder>Package-C</PackageFolder>
      <PackageNumber>01</PackageNumber>
    </Package>
    <Package>
      <PackageFolder>Package-D</PackageFolder>
      <PackageNumber>02</PackageNumber>
    </Package>
  </Sequence>
</Sequences>

In PoSh I read-in this XML by:

[xml]$xml = Get-Content -Path "PathToMyXmlFile"

I can get an object-like view by using the following code-line:

$xml.Sequences.GetEnumerator()

Screenshot of Command-Output:

Screenshot of Command-Output

At the moment I do not get any further, because I don't know how to select a node in my XML. For example I want to get the "PackageFolder" Package-A or the "PackageNumber" of Package-A. ($xml.Sequences."Sequence-A"...)

How to select those elements correctly? Is the design of the XML not usable for this?

Thank you!

Upvotes: 0

Views: 1334

Answers (2)

js2010
js2010

Reputation: 27546

An easy select-xml example.

(select-xml /Sequences/Sequence/Package file.xml).node

PackageFolder PackageNumber
------------- -------------
Package-A     01
Package-B     02
Package-C     01
Package-D     02

This gives you the same thing:

$xml.Sequences.Sequence.Package

Upvotes: 0

HAL9256
HAL9256

Reputation: 13493

PowerShell Data Basics: XML gives a good overview on accessing XML nodes. Basically, you have 2 ways of accessing the nodes, directly, or using XPATH.

Starting by loading your data:

[xml]$xml = @"
<?xml version="1.0" encoding="utf-8"?>
<Sequences>
  <Sequence>
    <SequenceName>Sequence-A</SequenceName>
    <SequenceNumber>01</SequenceNumber>
    <Package>
      <PackageFolder>Package-A</PackageFolder>
      <PackageNumber>01</PackageNumber>
    </Package>
    <Package>
      <PackageFolder>Package-B</PackageFolder>
      <PackageNumber>02</PackageNumber>
    </Package>
  </Sequence>
  <Sequence>
    <SequenceName>Sequence-B</SequenceName>
    <SequenceNumber>02</SequenceNumber>
    <Package>
      <PackageFolder>Package-C</PackageFolder>
      <PackageNumber>01</PackageNumber>
    </Package>
    <Package>
      <PackageFolder>Package-D</PackageFolder>
      <PackageNumber>02</PackageNumber>
    </Package>
  </Sequence>
</Sequences>
"@

Directly, involves needing to either directly access, or iterate through the nodes, e.g.:

PS C:\> $xml.Sequences.Sequence[0].Package[0]

PackageFolder PackageNumber
------------- -------------
Package-A     01

This means you have to know the order. The "Better" way is to iterate through the objects:

PS C:\> $SeqA = $xml.Sequences.Sequence | Where-Object { $_.SequenceName -eq "Sequence-A" }
PS C:\> $SeqA

SequenceName SequenceNumber Package
------------ -------------- -------
Sequence-A   01             {Package, Package}

PS C:\> $SeqA.Package | Where-Object { $_.PackageFolder -eq "Package-A" }

PackageFolder PackageNumber
------------- -------------
Package-A     01

Or the oneliner:

($xml.Sequences.Sequence | Where-Object { $_.SequenceName -eq "Sequence-A" }).Package | Where-Object { $_.PackageFolder -eq "Package-A" }

The second approach is to use XPATH, where you gain some flexibility for searching at the cost of ease of use:

$xml.SelectSingleNode("//Sequences/Sequence[contains(SequenceName, 'Sequence-A')]/Package[contains(PackageFolder, 'Package-A')]")

It all depends on how you want to use the object.

Upvotes: 2

Related Questions