Kapil
Kapil

Reputation: 987

Compare two xml elements of same parent node in powershell

<department>
    <employee name="ABC">
    <salary value="basic">5000</salary>
    <salary value="allowance">8000</salary>
    </employee>
    <employee name="XYZ">
    <salary value="basic">6000</salary>
    <salary value="allowance">3000</salary>
    </employee>
    </department>

How to get the employee names whose allowance is greater than basic in powershell.

I have tried below but does not give me the result

$result= $xml |Select-Xml '//department'| 
ForEach{
$basic=$_.Node.employee.salary.value | where {$_.Node.employee.salary.value -eq 'basic'}
$allowance=$_.Node.employee.salary.value | where {$_.Node.employee.salary.value -eq 'allowance'}
if ($allowance -ge $basic)
{
$name=$_.Node.employee.name
}
}
echo $result

Upvotes: 1

Views: 125

Answers (3)

AdminOfThings
AdminOfThings

Reputation: 25021

If you want to use Select-Xml, you can do the following:

$node = $xml | Select-Xml -XPath "//department/employee[./salary[@value='basic'] < ./salary[@value='allowance']]"
$node.node.name # Output the employee name

See XPath Examples for xpath expression examples. See Boolean, Comparison, and Set Expressions for more information on XPath operators including the escaping of < and > where necessary.

Upvotes: 4

js2010
js2010

Reputation: 27516

In your example, $_.Node.employee.salary.value is just an array of strings, so the where cmd can't reference any properties, and $basic and $allowance end up being blank. Also, the foreach only loops one time, because there's only one department.

This way, you're already piping in an array of employees, instead of the one department. I also get the node property out of the way. $basic and $allowance are still objects with value and #text properties. I output the employee object that matches. It's sort of like what you were trying to do. The comparison has to be [int], or else '500' is greater than '4000'.

(Select-Xml /department/employee salary.xml).node |
ForEach {
  $basic = $_.salary | where value -eq basic
  $allowance = $_.salary | where value -eq allowance
  if([int]$allowance.'#text' -ge $basic.'#text') {
    $_ | select name, 
      @{n='basic'; e={$basic.'#text'}}, 
      @{n='allowance'; e={$allowance.'#text'}} 
  }
}


name basic allowance
---- ----- ---------
ABC  5000  8000

Upvotes: 0

iRon
iRon

Reputation: 23763

I would use the PowerShell XML parser ([XML]) to create a XMLDocument:

$xml = [XML]'
    <department>
        <employee name="ABC">
            <salary value="basic">5000</salary>
            <salary value="allowance">8000</salary>
        </employee>
        <employee name="XYZ">
            <salary value="basic">6000</salary>
            <salary value="allowance">3000</salary>
        </employee>
    </department>'

Then it is as simple as:

$xml.Department.Employee | % {
    $allowance = [Int]($_.salary | ? {$_.value -eq 'allowance'}).'#text'
    $basic = [Int]($_.salary | ? {$_.value -eq 'basic'}).'#text'
    If ($allowance -ge $basic) {$Name = $_.name}
}

Upvotes: 0

Related Questions