0
votes

I'm writing a powershell script where i need to get some value of a node based on the parents' info (attribute names, id's..)

Example:

<?xml version="1.0" encoding="UTF-8"?>
<GrandParent>
    <Parent id="1">
        <foo></foo>
        <bar></bar>
        <buzz></buzz>
        <Child Name="correct">
            <Content>Value1</Content>
        </Child>
        <Child Name="wrong">
            <Content>Value2</Content>
        </Child>
        <Child Name="wrong">
            <Content>Value3</Content>
        </Child>
    </Parent>
    <Parent id="2">
        <foo></foo>
        <bar></bar>
        <buzz></buzz>
        <Child Name="correct">
            <Content>Value4</Content>
        </Child>
        <Child Name="wrong">
            <Content>Value5</Content>
        </Child>
        <Child Name="wrong">
            <Content>Value6</Content>
        </Child>
    </Parent>
    <Parent id="3">
        <foo></foo>
        <bar></bar>
        <buzz></buzz>
        <Child Name="correct">
            <Content>Value7</Content>
        </Child>
        <Child Name="wrong">
            <Content>Value8</Content>
        </Child>
        <Child Name="wrong">
            <Content>Value9</Content>
        </Child>
    </Parent>
</GrandParent>

I want to get some output like: Parent 1: value1 Parent 2: value4 Parent 3: value7

Explanation: for each Parent node i want to look at the 'Child' node with the 'Correct' name and get the value of his child

I'm looping with ForEach-Object inside a ForEach-Object, but my context '$_' always refers to the entire xml instead of the current scope:

$total_xml.GrandParent.Parent | ForEach-Oject {
   $_.Parent.Child | ForEach-Object{
      $_ #This refers back to the total_xml
   }
}

PS: I'm a newbie in Powershell scripting :(

Can someone help me out with a simple script for this?

2
Check out the -PipelineVariable common parameter. You're also looking at the wrong thing. Your first foreach should be $_.Child because $_ is referring to the Parent node and then your second foreach will be pointing at each Child node inside that Parent. - Maximilian Burszley

2 Answers

0
votes

Taking your example:

[xml] $xml = Get-Content -Path .\test.xml

You can get your desired output:

Parent 1: value1
Parent 2: value4
Parent 3: value7

Like so:

$Parents = @($xml.GrandParent.Parent)
for ($i = 0; $i -lt $Parents.Count; $i++) {
    "Parent ${i}: " + @($Parents[$i].Child).Where{$_.Name -eq 'Correct'}.Content
}

or using ForEach-Object (didn't notice the parents had ids):

$xml.GrandParent.Parent |
    ForEach-Object {
        "Parent $($_.id): " + @($_.Child).Where{$_.Name -eq 'Correct'}.Content
    }
0
votes

This is not best practice, but i like it because it is easily readable.

$xml = new-object -typename xml
$xml.Load("C:\temp\le.xml")
#To get stuff
$xml.GrandParent.Parent | Where-Object {$_.id -like 1}
#To edit stuff
($xml.GrandParent.Parent | Where-Object {$_.id -like 1}).foo = "test"
#To save stuff
$xml.Save("C:\temp\le.xml")