Trying to extract child node values from xml in Powershell
I have the following xml:
<?xml version="1.0"?>
<AdminDirectorUsers>
<Users>
<User>
<UserName>PC1</UserName>
<Installation>
<Products>
<Product>
<ProductID>Product1</ProductID>
<Selected>Yes</Selected>
</Product>
<Product>
<ProductID>Product2</ProductID>
<Selected>No</Selected>
</Product>
<Product>
<ProductID>Product3</ProductID>
<Selected>No</Selected>
</Product>
<Product>
<ProductID>Product4</ProductID>
<Selected>Yes</Selected>
</Product>
</Products>
</Installation>
</User>
<User>
<UserName>PC2</UserName>
<Installation>
<Products>
<Product>
<ProductID>Product1</ProductID>
<Selected>Yes</Selected>
</Product>
<Product>
<ProductID>Product2</ProductID>
<Selected>Yes</Selected>
</Product>
<Product>
<ProductID>Product3</ProductID>
<Selected>No</Selected>
</Product>
<Product>
<ProductID>Product4</ProductID>
<Selected>Yes</Selected>
</Product>
</Products>
</Installation>
</User>
</Users>
</AdminDirectorUsers>
I would like to loop through and extract a list of each UserName with all ProductIDs that has a sibling node Selected with a value of Yes, while ignoring the values of No.
$path = 'C:\Temp\test.xml'
$xml = New-Object -TypeName XML
$xml.Load($Path)
$UserNode = $xml.SelectNodes('//User')
$ProductNode = $xml.SelectNodes('//Product')
foreach ($PC in $usernode)
{
$PC.username
foreach($Node in $ProductNode){
# Test if selected == 'yes'
if($Node.Selected -eq 'yes') {
$Node.ProductID
}
}
}
My output is:
PC1
Product1
Product4
Product1
Product2
Product4
PC2
Product1
Product4
Product1
Product2
Product4
...but I'm looking for:
PC1
Product1
Product4
PC2
Product1
Product2
Product4
I've tried many ways to do this but nothing seems to work. What am I missing?
Change the second XPath expression used for the Product
/ProductID
to only get the descendants of a specific <User>
element, by anchoring against .
(the "current node"):
# Enumerate each `<User>` element
$xml |Select-Xml '//User' |%{
# Grab the exact username value
$username = $_.Node.UserName
# Then enumerate all descendant `<ProductID>` nodes who has a sibling `<Selected>Yes</Selected>` and attach username
$_.Node |Select-Xml './/ProductID[../Selected[. = "Yes"]]' |Select -Expand Node |Select @{Name='Username';Expression={$username}},InnerText
}
(I'm using Select-Xml
here but this works the same with the SelectNodes()
method)