Reputation: 140
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:
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
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
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